#include "file.h"
#include "atom.h"
#include "config.h"
+#ifdef HAVE_SOCKET
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+extern char *version;
#ifdef HAVE_LIBCRYPTO
#include <openssl/sha.h>
int method;
} __attribute__ ((packed));
+#ifdef HAVE_SOCKET
+static int
+file_socket_connect(char *host, char *service)
+{
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ int ret,fd,s;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = 0;
+ s = getaddrinfo(host, service, &hints, &result);
+ if (s != 0) {
+ dbg(0,"getaddrinfo error %s\n",gai_strerror(s));
+ return -1;
+ }
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (fd != -1) {
+ if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
+ break;
+ close(fd);
+ fd=-1;
+ }
+ }
+ freeaddrinfo(result);
+ return fd;
+}
+#endif
+
+static int
+file_http_request(struct file *file, char *host, char *path)
+{
+ char *request=g_strdup_printf("GET %s HTTP/1.0\r\nUser-Agent: navit %s\r\nHost: %s\r\n\r\n",path,version,host);
+ write(file->fd, request, strlen(request));
+ file->requests++;
+}
+
+static char *
+file_http_header_end(char *str, int len)
+{
+ int i;
+ for (i=0; i+1<len; i+=2) {
+ if (str[i+1]=='\n') {
+ if (str[i]=='\n')
+ return str+i+2;
+ else if (str[i]=='\r' && i+3<len && str[i+2]=='\r' && str[i+3]=='\n')
+ return str+i+4;
+ --i;
+ } else if (str[i+1]=='\r') {
+ if (i+4<len && str[i+2]=='\n' && str[i+3]=='\r' && str[i+4]=='\n')
+ return str+i+5;
+ --i;
+ }
+ }
+ return NULL;
+}
+
struct file *
file_create(char *name, enum file_flags flags)
{
file->name = g_strdup(name);
if (flags & file_flag_url) {
-#ifndef HAVE_API_WIN32_BASE
- char *cmd=g_strdup_printf("curl '%s'",name);
- file->stdfile=popen(cmd,"r");
- file->fd=fileno(file->stdfile);
- file->special=1;
- g_free(cmd);
+#ifdef HAVE_SOCKET
+ if (!strncmp(name,"http://",7)) {
+ char *host=g_strdup(name+7);
+ char *port=strchr(host,':');
+ char *path=strchr(name+7,'/');
+ if (path)
+ host[path-name-7]='\0';
+ if (port)
+ *port++='\0';
+ dbg(0,"host=%s path=%s\n",host,path);
+ file->fd=file_socket_connect(host,port?port:"80");
+ file_http_request(file,host,path);
+ file->special=1;
+ g_free(host);
+ }
#endif
} else {
file->fd=open(name, open_flags);
}
+static void
+file_process_headers(struct file *file, char *headers)
+{
+ char *tok;
+ char *cl="Content-Length: ";
+ while (tok=strtok(headers, "\r\n")) {
+ if (!strncasecmp(tok,cl,strlen(cl))) {
+ file->size=atoll(tok+strlen(cl));
+ }
+ headers=NULL;
+ }
+}
+
unsigned char *
file_data_read_special(struct file *file, int size, int *size_ret)
{
- void *ret;
+ char *ret,*hdr;
+ int rets=0,rd;
if (!file->special)
return NULL;
ret=g_malloc(size);
- *size_ret=read(file->fd, ret, size);
+ while (size > 0) {
+ rd=read(file->fd, ret+rets, size);
+ if (rd <= 0)
+ break;
+ rets+=rd;
+ size-=rd;
+ if (file->requests) {
+ if (hdr=file_http_header_end(ret, rets)) {
+ hdr[-1]='\0';
+ file_process_headers(file, ret);
+ rets-=hdr-ret;
+ memmove(ret, hdr, rets);
+ file->requests--;
+ } else {
+ rets=0;
+ break;
+ }
+ }
+ }
+ *size_ret=rets;
return ret;
}
{
switch (f->special) {
case 0:
- close(f->fd);
- break;
-#ifndef HAVE_API_WIN32_BASE
case 1:
- pclose(f->stdfile);
+ close(f->fd);
break;
-#endif
}
if ( f->begin != NULL )
char *html;
struct file *f;
int size;
+ int mode=0;
if (!in || !in[0] || !ATTR_IS_STRING(in[0]->type) || !in[0]->u.str)
return;
+ if (in[1] && ATTR_IS_INT(in[1]->type))
+ mode=in[1]->u.num;
f=file_create(in[0]->u.str, file_flag_url);
if (! f)
return;
- html=file_data_read_special(f, 8192, &size);
- if (size < 8192) {
- html[size]='\0';
- printf("%s\n",html);
- gui_internal_html_menu(this, html, NULL);
+ if (mode) {
+ FILE *fm=fopen("map.bin","wb");
+ char *data;
+ long long downloaded=0;
+ for (;;) {
+ data=file_data_read_special(f, 8192, &size);
+ if (size) {
+ if (fwrite(data, size, 1, fm) != 1) {
+ dbg(0,"write error\n");
+ break;
+ }
+ downloaded+=size;
+ dbg(0,"%Ld of %Ld\n",downloaded,f->size);
+ }
+ g_free(data);
+ if (!size)
+ break;
+ }
+ fclose(fm);
+ } else {
+ html=file_data_read_special(f, 8192, &size);
+ if (size < 8192) {
+ html[size]='\0';
+ printf("%s\n",html);
+ gui_internal_html_menu(this, html, NULL);
+ }
+ g_free(html);
}
- g_free(html);
file_destroy(f);
}
-
/**
* @brief handles the 'next page' table event.
* A callback function that is invoked when the 'next page' button is pressed
{"quit",command_cast(gui_internal_cmd2_quit)},
{"write",command_cast(gui_internal_cmd_write)},
{"about",command_cast(gui_internal_cmd2_about)},
- {"map_downloader",command_cast(gui_internal_cmd_map_downloader)}
+ {"map_downloader",command_cast(gui_internal_cmd_map_downloader)},
};