/* Copyright (C) 2000-2003 Markus Lausser (sgop@users.sf.net) This is free software distributed under the terms of the GNU Public License. See the file COPYING for details. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBLCONV_H #include #endif #include "lopster.h" #include "global.h" #include "support.h" #include "transfer.h" #include "connection.h" #include "handler.h" #include "log.h" #include "chat.h" #include "resume.h" #include "userinfo.h" #include "scheme.h" #include "dialog.h" #include "string_list.h" #include "whois.h" #include "share2.h" #include "callbacks.h" #include "interface.h" #include "subscription.h" #include "statistic.h" #include "browse.h" #include "server.h" #include "search.h" #include "ping.h" #include "preferences.h" #include "file_tree.h" #include "utils.h" #include "files.h" #include "mtypes.h" //#undef AVANCED_CONNECTION /**opennap Diagram: U = uploader, S = server, D = downloader. U-S = uploader to server (opennap) _U-S___S-U___U-D | | accept / 608 501 CON | | _S-D___D-S___S-U_/ | firewalled / 204 500 607 \ | download / \_U-S___S-D___D | | / 620 620 QUE | | remotely queued D-S 203 \ _U-S___S-D___D-U | | accept \ / 608 204 CON | | \_S-U_/ | non-firewalled 607 \ | download \_U-S___S-D___D | | 619 620 QUE | | remotely queued (slavanap) _U-S___S-D___D-S___S-U___U-D | | accept / 608 204 500 501 CON | | _S-U_/ | firewalled / 607 \ | download / \_U-S___S-D___D | | / 619 620 QUE | | remotely queued D-S 203 \ _U-S___S-D___D-U | | accept \ / 608 204 CON | | \_S-U_/ | non-firewalled 607 \ | download \_U-S___S-D___D | | 619 620 QUE | | remotely queued (slavanap, more simple) _D-S___S-U___U-D / 500 501 CON _U-S___S-D_/ / 608 204 \ D-S___S-U_/ \_D-U 203 607 \ CON \ \_U-S___S-D___D 620 620 QUE */ /* for vfat compatibility */ #if !defined(O_BINARY) # define O_BINARY 0 #endif #define SPEED_LIFE 60 #define RESUME_CHECK_LENGTH 100 #define MAP_SIZE 1024*1024 static void create_percent_win(); static download_t* popup_download = NULL; static GdkColor* back0 = NULL; static GdkColor* back1 = NULL; static GdkColor* back2 = NULL; static GdkGC* trans_gc = NULL; static int check_uploads = 0; const int StatusInfo[S_NUMBER] = { T_NONE, T_CURRENT, T_CURRENT, T_NONE, T_NONE, T_TRANSFER, T_TRANSFER, T_NONE, T_NONE, T_NONE, T_NONE, T_CURRENT, T_NONE, T_NONE, T_NONE, T_NONE, T_NONE, T_NONE, T_NONE, T_NONE }; const int StatusDist[4][4] = { {0, 1, 0, 1}, {-1, 0, -1, 0}, {0, 1, 0, 1}, {-1, 0, -1, 0} }; char *status_names(int status) { switch (status) { case S_CONNECTING: return "Connecting..."; case S_INFO: return "Getting info..."; case S_DOWNLOADING: return "Downloading"; case S_CANCELED: return "Canceled"; case S_PART: return "Finished"; case S_FINISHED: return "Finished"; case S_TIMEOUT: return "Timeout"; case S_REJECT: return "Rejected"; case S_INCOMPLETE: return "Incomplete"; case S_UPLOADING: return "Uploading"; case S_WAITING: return "Waiting"; case S_FIREWALL: return "Both Firewalled"; case S_CONERROR: return "Connection Error"; case S_QUEUED: return "Queued"; case S_REMOTE: return "Remotely Queued"; case S_UNAVAILABLE: return "Unavailable"; case S_RESUME_ERR: return "Resume Error"; case S_DELETE: return "Deleted"; case S_IO: return "IO error"; case S_REQUESTED: return "Recently requested"; default: return "unknown status"; } } ///////////////////////////////////// static void transfer_init_colors(GtkCList* clist) { style_t* style1; style_t* style2; int height; int i1; if (back0) g_free(back0); if (back1) g_free(back1); if (back2) g_free(back2); height = clist->row_height; if (!trans_gc) trans_gc = gdk_gc_new(global.win->window); style1 = style_get(global.scheme, "transfer_bar1"); style2 = style_get(global.scheme, "transfer_bar2"); back0 = g_malloc(sizeof(GdkColor)*(height+1)/2); back1 = g_malloc(sizeof(GdkColor)*(height+1)/2); back2 = g_malloc(sizeof(GdkColor)*(height+1)/2); for (i1 = 0; i1 < (height+1)/2; i1++) { back0[i1].pixel = 0; back0[i1].red = 0xbf00/height*(height-i1); back0[i1].green = 0xbf00/height*(height-i1); back0[i1].blue = 0xbf00/height*(height-i1); gdk_color_alloc (gtk_widget_get_colormap(GTK_WIDGET(clist)), &(back0[i1])); back1[i1].pixel = 0; back1[i1].red = style1->back->red/height*(height-i1); back1[i1].green = style1->back->green/height*(height-i1); back1[i1].blue = style1->back->blue/height*(height-i1); gdk_color_alloc (gtk_widget_get_colormap(GTK_WIDGET(clist)), &(back1[i1])); back2[i1].pixel = 0; back2[i1].red = style2->back->red/height*(height-i1); back2[i1].green = style2->back->green/height*(height-i1); back2[i1].blue = style2->back->blue/height*(height-i1); gdk_color_alloc (gtk_widget_get_colormap(GTK_WIDGET(clist)), &(back2[i1])); } gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(clist)), style1->fore); gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(clist)), style2->fore); } static void transfer_reset(transfer_t* data, int pos) { int i1; for (i1 = 0; i1 < TRANSFER_HISTORY_TIME; i1++) data->history[i1] = pos; data->hist_cnt = 0; data->hist_pos = 0; } void transfer_init(transfer_t* trans, int status) { trans->user_info = NULL; trans->rate = 0; trans->timeleft = 0; trans->start_time = 0; trans->stop_time = 0; trans->transferred = 0; trans->status = status; trans->is_dcc = FALSE; trans->needs_update = 1; transfer_reset(trans, 0); } void transfer_destroy(transfer_t* data) { if (!data) return; g_free(data); } upload_t *upload_new(net_t* net, char* filename, char* user, int offline) { upload_t *upload; struct stat st; upload = g_malloc(sizeof(upload_t)); transfer_init(TRANS(upload), S_REQUESTED); upload->nu.net = net; upload->file = file_create_from_local(filename); TRANS(upload)->user_info = user_info_detect(net, user); upload->nu.user = g_strdup(user); upload->offline = offline; upload->fd = NULL; upload->segment = NULL; upload->access = NULL; upload->node = NULL; #ifdef ADVANCED_CONNECTION upload->advanced = 0; #endif if (stat(upload->file->longname, &st) >= 0) { upload->file->size = st.st_size; } return upload; } void upload_destroy(upload_t *upload) { if (!upload) return; #ifdef TRANSFER_DEBUG printf("[UPLOAD] destroying %p\n", upload); #endif if (upload->file) file_destroy(upload->file); transfer_destroy(TRANS(upload)); } void upload_hide(socket_t * socket) { GtkCList *clist; int row; if (!socket) return; if (socket->type != S_UPLOAD) return; clist = GTK_CLIST(lookup_widget(global.win, "transfer_up")); row = gtk_clist_find_row_from_data(clist, socket); if (row < 0) { g_warning("upload_hide(): transfer not found"); return; } gtk_clist_remove(clist, row); } int transfer_in_progress(transfer_t * trans) { if ((StatusInfo[trans->status] == T_CURRENT) || (StatusInfo[trans->status] == T_TRANSFER)) return 1; else return 0; } int transfer_status_dist(int s1, int s2) { return StatusDist[StatusInfo[s1]][StatusInfo[s2]]; } void print_transfer_prefix(chat_page_t* page, int down, char* text2, char* text3, char* nick, net_t* net, char* longname, char* shortname, char* nick2, net_t* net2) { if (!nick) nick = "_unknown_"; chat_print_time_stamp(page, M_PUBLIC); chat_print_prefix(page, 1); chat_print_text(page, M_PUBLIC, "message", "("); /* if (down) chat_print_text(page, M_PUBLIC, "text", "download"); else chat_print_text(page, M_PUBLIC, "text", "upload"); chat_print_text(page, M_PUBLIC, "message", "!"); */ chat_print_text_w(page, M_PUBLIC, "text", text2, down?12:10); chat_print_text(page, M_PUBLIC, "message", " - "); chat_print_text_w(page, M_PUBLIC, "text", text3, down?10:10); chat_print_text(page, M_PUBLIC, "message", ") "); chat_print_text(page, M_PUBLIC, "user", "<"); chat_print_nick(page, M_PUBLIC, nick, net); chat_print_text_w(page, M_PUBLIC, "user", "> ", 20-strlen(nick)); if (nick2) { chat_print_text(page, M_PUBLIC, "text", "for"); chat_print_text(page, M_PUBLIC, "user", " <"); chat_print_nick(page, M_PUBLIC, nick2, net2); chat_print_text(page, M_PUBLIC, "user", ">"); } else if (longname) { // chat_print_text(page, M_PUBLIC, "text", " "); // chat_print_time_stamp(page, M_PUBLIC); // chat_print_colored(page, M_PUBLIC, "message", prefix); // chat_print_text_w(page, M_PUBLIC, "message", " ", 7); chat_print_text(page, M_PUBLIC, "user", "("); chat_print_file(page, longname, shortname); chat_print_text(page, M_PUBLIC, "user", ")"); } chat_print_text(page, M_PUBLIC, "text", "\n"); } void check_uploads_again() { check_uploads = 1; } void upload_status_set(socket_t * socket, int status) { upload_t *upload; int add; style_t *style; double val; char str[1024]; chat_page_t *page; file_t* file; GtkCList *clist; int row; transfer_t* trans; if (!socket || !socket->data) return; upload = socket->data; trans = TRANS(upload); add = transfer_status_dist(trans->status, status); if (add != 0) { int size; if (add < 0) check_uploads_again(); if (trans->user_info) trans->user_info->cur[1] += add; global.limit.cur_uploads += add; if (upload->segment) size = upload->segment->stop - upload->segment->start; else size = upload->file->size; if (size >= global.limit.large_size *1024 *1024) global.limit.cur_large += add; } if (status == S_UPLOADING) { /* count upload as access now if flag is set */ if (global.options.access_transferring) access_new_request(upload); ext_handle(EVENT_UPLOAD_START, trans->user_info->nick, upload->file->longname); command_send(NULL, CMD_UPLOAD_START); global.limit.cur_real_uploads++; trans->user_info->real_cur[1]++; trans->start_time = global.current_time; trans->transferred = 0; } else if (add > 0) { trans->start_time = global.current_time; } if (trans->status == S_UPLOADING) { command_send(NULL, CMD_UPLOAD_END); global.limit.cur_real_uploads--; trans->user_info->real_cur[1]--; trans->stop_time = global.current_time; } file = upload->file; if (status == S_UPLOADING) { l_log(NULL, "uploads", LOG_OTHER, "Uploading [%s] to [%s]%s at [%ld]\n", file->shortname, trans->user_info->nick, trans->is_dcc ? " (DCC)" : "", upload->segment->start); if ((global.options.no_piping & NOPIPE_UPLOAD) == 0) { if (global.options.piping & PIPE_UPLOAD) { page = chat_page_search(NULL, "Uploads", P_OTHER, 3); if (!page) page = create_other_page(NULL, "Uploads", "Uploads"); } else { page = chat_page_get_printable();; } print_size(str, upload->segment->start ? upload->segment->start : upload->segment->stop-upload->segment->start); print_transfer_prefix(page, 0, upload->segment->start ? "resume":"start", str, upload->nu.user, upload->nu.net, file->longname, file->filename, NULL, NULL); } } else if (trans->status == S_UPLOADING) { if (trans->stop_time - trans->start_time > 0) val = trans->transferred / (trans->stop_time - trans->start_time); else val = 0; print_speed(str, val, 1); l_log(NULL, "uploads", LOG_OTHER, "Ending [%s] to [%s]%s :%s: [%ld] (%s)\n", file->shortname, trans->user_info->nick, trans->is_dcc ? " (DCC)" : "", status_names(status), trans->transferred, str); if ((global.options.no_piping & NOPIPE_UPLOAD) == 0) { if (global.options.piping & PIPE_UPLOAD) { page = chat_page_search(NULL, "Uploads", P_OTHER, 3); if (!page) page = create_other_page(NULL, "Uploads", "Uploads"); } else { page = chat_page_get_printable(); } print_transfer_prefix(page, 0, status_names(status), str, upload->nu.user, upload->nu.net, file->longname, file->filename, NULL, NULL); } } trans->status = status; upload_update(socket); clist = GTK_CLIST(lookup_widget(global.win, "transfer_up")); row = gtk_clist_find_row_from_data(clist, socket); if (row < 0) return; if ((socket->timer >= 0) || (trans->status == S_QUEUED)) { style = style_get(global.scheme, "transfer_waiting"); if (style) { gtk_clist_set_background(clist, row, style->back); gtk_clist_set_foreground(clist, row, style->fore); } } else { if (transfer_in_progress(TRANS(upload))) { style = style_get(global.scheme, "transfer_running"); if (style) { gtk_clist_set_background(clist, row, style->back); gtk_clist_set_foreground(clist, row, style->fore); } } else { gtk_clist_set_background(clist, row, NULL); gtk_clist_set_foreground(clist, row, NULL); } } } socket_t *upload_search_mapable(net_t* net ATTR_UNUSED, char *user, char *winname) { socket_t *socket; upload_t *upload; GList *dlist; file_t* file; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = (socket_t *) (dlist->data); if (socket->type != S_UPLOAD) continue; upload = socket->data; if (!upload) continue; file = upload->file; // printf("dest [%s][%s] %d\n", transfer->user, transfer->winname, transfer->status); if (!g_strcasecmp(file->winname, winname) && !g_strcasecmp(TRANS(upload)->user_info->nick, user) && // testing: do not check the network // && (!net || (upload->nu.net == net)) (!transfer_in_progress(TRANS(upload)) || (TRANS(upload)->status == S_WAITING))) return socket; } return NULL; } int upload_to_destroy(socket_t * socket, int mode) { if (socket->timer >= 0) return 0; switch (mode) { case S_FINISHED: if (global.options.ul_autoremove & REMOVE_U_FINISHED) return 1; break; case S_REJECT: case S_REMOTE: case S_TIMEOUT: case S_INCOMPLETE: case S_FIREWALL: case S_CONERROR: case S_UNAVAILABLE: case S_RESUME_ERR: case S_IO: case S_CANCELED: if (global.options.ul_autoremove & REMOVE_U_ABORTED) return 1; break; case S_DELETE: return 1; break; } return 0; } int upload_eject(upload_t* request, int just_test) { int add = transfer_status_dist(TRANS(request)->status, S_QUEUED); GList* dlist; socket_t* socket; upload_t* upload; socket_t* loser = NULL; upload_t* losert = NULL; int loser_priority; int priority; int pri; chat_page_t* page; file_t* file = request->file; int large_only = 0; if (file->size > global.limit.large_size*1024*1024 && global.limit.max_large <= global.limit.cur_large + add) { large_only = 1; } priority = user_info_priority(TRANS(request)->user_info, NULL); loser_priority = priority; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket) continue; if (socket->type != S_UPLOAD) continue; upload = socket->data; if (!upload) continue; if (upload == request) continue; // searching for a started/running upload if (!transfer_in_progress(TRANS(upload))) continue; if (TRANS(upload)->is_dcc) continue; if (large_only && upload->file->size <= global.limit.large_size*1024*1024) continue; pri = user_info_priority(TRANS(upload)->user_info, NULL); // make sure that we eject the latest upload if (pri < loser_priority || (losert && pri == loser_priority && TRANS(losert)->start_time < TRANS(upload)->start_time)) { if (just_test) return priority; loser = socket; losert = upload; loser_priority = pri; } } if (loser) { l_log(NULL, "uploads", LOG_OTHER, "Ejecting [%s] for [%s]\n", TRANS(losert)->user_info->nick, TRANS(request)->user_info->nick); if ((global.options.no_piping & NOPIPE_UPLOAD) == 0) { if (global.options.piping & PIPE_UPLOAD) { page = chat_page_search(NULL, "Uploads", P_OTHER, 3); if (!page) page = create_other_page(NULL, "Uploads", "Uploads"); } else { page = chat_page_get_printable(); } print_transfer_prefix(page, 0, "eject", " ", losert->nu.user, losert->nu.net, NULL, NULL, request->nu.user, request->nu.net); } socket_end(loser, S_CANCELED); return priority; } else { return -1; } } int free_slot(int large, int free_up, int free_large) { if (large && free_up && free_large) return 1; else if (!large && free_up) return 1; else return 0; } static int upload_allowed(upload_t * upload) { int add = transfer_status_dist(TRANS(upload)->status, S_QUEUED); int large; int free_up, free_large; char* found; subscription_t* sub; user_info_t* userinfo; file_t *file; int friend = 0; int limit; if (global.status.exiting == E_SAFE) return -1; file = upload->file; userinfo = TRANS(upload)->user_info; if (string_list_search(LIST_ENEMY, userinfo->nick)) return -1; // check per user limit if (userinfo->max[1] == -1) limit = global.limit.default_uploads; else limit = userinfo->max[1]; if (limit > 0 && userinfo->cur[1] + add >= limit) return -1; // now check for subscriptions sub = subscription_lookup_file(userinfo->nick, file->longname, &found); if (sub && !found) return -1; // at last test whether it is a friend, always allow him, even if // there was no upload ejected if (string_list_search(LIST_FRIEND, userinfo->nick)) friend = 1; if (sub && sub->friend_while_subs) friend = 1; // allow friends, even if there is no free slot right now. if (friend) return 1; if (file->size > global.limit.large_size*1024*1024) large = 1; else large = 0; if (global.limit.max_uploads > 0 && global.limit.max_uploads <= global.limit.cur_uploads + add) free_up = 0; else free_up = 1; if (global.limit.max_large > 0 && global.limit.max_large <= global.limit.cur_large + add) free_large = 0; else free_large = 1; // if free slot return now if (free_slot(large, free_up, free_large)) return 1; // all other cases, return 0; return 0; } void upload_show(socket_t * socket) { GtkCList *temp; int row; upload_t *upload = socket->data; file_t* file; transfer_t* data; temp = GTK_CLIST(lookup_widget(global.win, "transfer_up")); row = gtk_clist_find_row_from_data(temp, socket); if (row >= 0) return; file = upload->file; data = TRANS(upload); strcpy(tstr[0], file->shortname); print_size(tstr[1], file->size); sprintf(tstr[2], "[%s] %s", upload->nu.net?NetType[upload->nu.net->type]:"?", data->user_info->nick); strcpy(tstr[4], LineSpeed(data->user_info->linespeed)); tstr[3][0] = tstr[5][0] = tstr[6][0] = 0; row = gtk_clist_append(temp, list); gtk_clist_set_row_data(temp, row, (gpointer) socket); upload_update(socket); } static int estimate_upload_position(upload_t *upl) { GtkCList* clist; int row, pos; upload_t* upload; socket_t* socket; clist = GTK_CLIST(lookup_widget(global.win, "transfer_up")); for (pos = row = 0; row < clist->rows; row++) { socket = gtk_clist_get_row_data(clist, row); if (!socket || socket->type != S_UPLOAD) continue; upload = socket->data; if (upload == upl) break; if (!upload->offline && TRANS(upload)->status == S_QUEUED) pos++; } return pos + 1; } void upload_start(socket_t * socket) { upload_t *upload = socket->data; file_t* file; if (!NET_CONNECTED(upload->nu.net)) { g_warning("upload_start(): (%s) not logged on that net: %s", upload->file->shortname, upload->nu.net?upload->nu.net->name:"null"); return; } socket->cnt = 0; socket->max_cnt = global.network.transfer_timeout_up; file = upload->file; #ifdef TRANSFER_DEBUG printf("[UPLOAD] starting [%s]\n", file->winname); #endif if (!TRANS(upload)->is_dcc) { command_send(upload->nu.net, CMD_UPLOAD_OK, upload->nu.user, file->winname); } upload_status_set(socket, S_WAITING); } FILE *upload_open_file(upload_t * upload) { char *filename; file_t* file; file = upload->file; filename = file->longname; upload->fd = fopen(filename, "rb"); #ifdef ADVANCED_CONNECTION upload->advanced = 0; #endif if (upload->fd != NULL) { #ifdef TRANSFER_DEBUG printf("[UPLOAD] seeking to %d\n", upload->segment->start); #endif if (fseek(upload->fd, upload->segment->start, SEEK_SET) == -1) { fclose(upload->fd); upload->fd = NULL; g_warning("upload_open_file(): could not seek in file [%s] to %d\n", filename, upload->segment->start); } } else { g_warning("upload_open_file(): could not open [%s]\n", filename); } upload->segment->size = 0; return upload->fd; } void upload_end(socket_t * socket, int mode) { upload_t *upload = socket->data; transfer_t* trans = TRANS(upload); if (!upload) return; #ifdef TRANSFER_DEBUG printf("[UPLOAD] ending (mode %d) [%s][%s]\n", mode, upload->file->longname, trans->user_info->nick); #endif if (upload->fd) { fclose(upload->fd); upload->fd = NULL; } upload_status_set(socket, mode); if (upload->segment) { access_finished_request(upload); trans->timeleft = trans->stop_time - trans->start_time; if (trans->timeleft > 0) trans->rate = trans->transferred / trans->timeleft; else trans->rate = 0; file_segment_destroy(upload->segment); upload->segment = NULL; } upload_update(socket); } #define MAX_PUSH 20240 long upload_calc_max(user_info_t* userinfo) { long m1; long m2; long limit; long bytes; int act_limit = global.up_width.limit - global.down_width.value/100*global.limit.download_percent; if (act_limit < global.up_width.limit/2) act_limit = global.up_width.limit/2; if (userinfo->limit[1]) { if (userinfo->limit[1] <= userinfo->bytes[1]) { // if user limit exceeded, then disable upload return 0; } else { // else set max bytes to differnce to limit-already_downloaded m1 = userinfo->limit[1] - userinfo->bytes[1]; } } else m1 = MAX_PUSH; bytes = global.up_width.bytes[0] + global.up_width.bytes[1]; // check global limit if (userinfo->ignore_global[1]) { // ignore limit for user m2 = MAX_PUSH; } else if (bytes >= act_limit) { return 0; } else { m2 = act_limit - bytes; } if (m2 < m1) m1 = m2; // m1 now is max allowed for this user // evenly divide bandwidth for the uploads. if (global.limit.cur_real_uploads <= 0) { g_warning("cur_real_uploads shouldnt be <= 0"); limit = act_limit/4; } else { limit = act_limit/global.limit.cur_real_uploads/4; } if (m1 > limit) m1 = limit; if (m1 > MAX_PUSH) m1 = MAX_PUSH; return m1; } gint upload_push_output(gpointer data, gint source, GdkInputCondition condition) { socket_t *socket = data; upload_t *upload = socket->data; transfer_t* trans = TRANS(upload); char buf[MAX_PUSH + 1]; int n, sent; long maxpush; if (condition != GDK_INPUT_WRITE) { socket_end(socket, S_INCOMPLETE); return 1; } maxpush = upload_calc_max(trans->user_info); if (maxpush <= 0) { gdk_input_remove(socket->output); socket->output = -1; return 1; } if (maxpush > upload->segment->stop - upload->segment->start - upload->segment->size) maxpush = upload->segment->stop - upload->segment->start - upload->segment->size; if (maxpush > 0) { // fseek(trans->file, upload->progress, SEEK_SET); n = fread(buf, 1, maxpush, upload->fd); if (n <= 0) { g_warning("upload_push_output(): IO_ERROR: [%s]", upload->file->longname); g_warning("\tcould read %ld bytes at position %d", maxpush, upload->segment->start+upload->segment->size); socket_end(socket, S_IO); return 1; } if ((sent = send_safe(source, buf, 1, n)) == -1) { socket_end(socket, S_INCOMPLETE); return 1; } else { socket->cnt = 0; upload->segment->size += sent; if (sent != n) { // have to re-set the read position fseek(upload->fd, upload->segment->start+upload->segment->size, SEEK_SET); } } global.up_width.bytes[0] += sent; trans->user_info->bytes[1] += sent; trans->transferred += sent; } // now check whether we have reached the segment end. if (upload->segment->start + upload->segment->size >= upload->segment->stop) { #ifdef ADVANCED_CONNECTION if (upload->advanced == 1) { // keep the connection alive gdk_input_remove(socket->output); socket->output = -1; upload->advanced = 2; } else #endif socket_end(socket, S_FINISHED); } return 1; } #ifdef ADVANCED_CONNECTION gint upload_get_advanced(gpointer data, gint source, GdkInputCondition condition) { socket_t *socket = data; upload_t* upload = socket->data; int val; int val1=0, val2=0; char buf[MAX_PUSH + 1]; int len; if (condition != GDK_INPUT_READ) { socket_end(socket, S_INCOMPLETE); return 1; } // now receive.. if (recv_safe(source, buf, 4, 4) != 4) { #ifdef TRANSFER_DEBUG printf("*** [ADVANCED] could not read 4 bytes\n"); #endif socket_end(socket, S_INCOMPLETE); return 1; } memcpy(&(len), buf, 4); len = BSWAP32(len); if (recv_safe(source, buf, len, len) != len) { #ifdef TRANSFER_DEBUG printf("*** [ADVANCED] could not read %d bytes\n", len); #endif socket_end(socket, S_INCOMPLETE); return 1; } buf[len] = 0; #ifdef TRANSFER_DEBUG printf("#### read [%s]\n", buf); #endif if (!strncmp(buf, "STOP", 4)) { upload->advanced = 1; val = atoi(buf+5); // update large counter if (upload->segment->stop - upload->segment->start >= global.limit.large_size *1024 *1024) val1 = 1; if (val - upload->segment->start >= global.limit.large_size *1024 *1024) val2 = 1; global.limit.cur_large += val2-val1; upload->segment->stop = val; if (upload->segment->stop < upload->segment->start+upload->segment->size) { // we have already sent more bytes, cancel the upload! socket_end(socket, S_INCOMPLETE); return 1; } } else if (!strncmp(buf, "START", 5)) { if (upload->advanced != 2) printf("**** START error\n"); val = atoi(buf+5); // update large counter if (upload->segment->stop - upload->segment->start >= global.limit.large_size *1024 *1024) val1 = 1; if (upload->file->size - val >= global.limit.large_size *1024 *1024) val2 = 1; global.limit.cur_large += val2-val1; file_segment_destroy(upload->segment); upload->segment = file_segment_new(val, upload->file->size); // seek to the new position #ifdef TRANSFER_DEBUG printf("[ADVANCED] seeking to %d\n", upload->segment->start); #endif if (fseek(upload->fd, upload->segment->start, SEEK_SET) == -1) { printf("*** [ADVANCED] could not seek to %d\n", upload->segment->start); socket_end(socket, S_IO); return 1; } transfer_reset(TRANS(upload), upload->segment->start); socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(upload_push_output), socket); if (send_safe(source, "CONTINUED", 9, 9) != 9) { socket_end(socket, S_INCOMPLETE); return 1; } } else if (!strncmp(buf, "FINISHED", 8)) { socket_end(socket, S_FINISHED); return 1; } else { printf("invalid token received\n"); } return 1; } #endif gint upload_fw_get_info(gpointer data, gint source, GdkInputCondition condition) { #ifndef HAVE_LIBLCONV_H char buffer[1025]; #else char buffer[2047]; char lconv_buf[2047]; #endif int cnt; socket_t *socket = (socket_t *) data; socket_t *socket2; char *username; char *filename; char *progress; file_t *file; upload_t *upload; struct stat st; char *temp_str; file_node_t* node; transfer_t* trans; if (condition != GDK_INPUT_READ) { socket_destroy(socket, 0); return 1; } gdk_input_remove(socket->input); socket->input = -1; cnt = 0; switch (cnt = recv(source, buffer, 1024, 0)) { case -1: case 0: socket_destroy(socket, 0); return 1; default: break; } buffer[cnt] = 0; #ifdef HAVE_LIBLCONV_H if (global.options.use_iconv) { lconv_conv(LCONV_SPEC, local_codeset, global.options.dest_codeset, lconv_buf, buffer); strcpy(buffer, lconv_buf); } #endif #ifdef TRANSFER_DEBUG printf("[UPLOAD] firewall info [%s]\n", buffer); #endif username = arg(buffer, 0); filename = arg(NULL, 0); progress = arg(NULL, 0); if (!progress) { socket_destroy(socket, 0); return 1; } socket2 = upload_search_mapable(NULL, username, filename); if (socket2) { upload = socket2->data; trans = TRANS(upload); if (trans->status != S_WAITING) { socket_destroy(socket, S_DELETE); return 1; } if (string_list_search(LIST_ENEMY, trans->user_info->nick)) { socket_destroy(socket, S_DELETE); return 1; } // make sure to reset the destination transfer first if (socket2->fd >= 0) close(socket2->fd); socket2->fd = socket->fd; // should be -1 socket->fd = -1; if (socket2->input >= 0 || socket2->output >= 0) { g_warning("upload_fw_get_info(): upload already has socket IOs"); } if (socket2->timer >= 0) gtk_timeout_remove(socket2->timer); socket2->timer = -1; socket2->ip_long = socket->ip_long; socket2->port = socket->port; socket_destroy(socket, S_DELETE); socket = socket2; socket->cnt = 0; upload_status_set(socket, S_INFO); } else { socket_destroy(socket, S_DELETE); return 1; } node = file_tree_search_filename(FILE_TREE(global.lib), upload->file->longname); if (node || trans->is_dcc) file = upload->file; else file = NULL; if (!trans->is_dcc && (!node || ((node->flags & LIB_SHARED) == 0))) { #ifdef TRANSFER_DEBUG printf("[UPLOAD] *FILE NOT SHARED*\n"); #endif // dont check return value here... send_safe(socket->fd, "FILE NOT SHARED", 0, strlen("FILE NOT SHARED")); socket_end(socket, S_UNAVAILABLE); return 1; } else if (stat(file->longname, &st) < 0) { #ifdef TRANSFER_DEBUG printf("[UPLOAD] *FILE NOT FOUND*\n"); #endif // dont check return value here.. send_safe(socket->fd, "FILE NOT FOUND", 0, strlen("FILE NOT FOUND")); socket_end(socket, S_IO); return 1; } //#ifdef ADVANCED_CONNECTION // temp_str = g_strdup_printf("0%ld", upload->file->size); //#else temp_str = g_strdup_printf("%ld", upload->file->size); //#endif #ifdef TRANSFER_DEBUG printf("[UPLOAD] sending size %s\n", temp_str); #endif if (send_safe(socket->fd, temp_str, strlen(temp_str), strlen(temp_str)) == -1) { socket_end(socket, S_IO); g_free(temp_str); return 1; } g_free(temp_str); upload->segment = file_segment_new(strtol(progress, NULL, 10), upload->file->size); // check whether this is still a large upload if (upload->file->size >= global.limit.large_size *1024 *1024 && upload->segment->stop - upload->segment->start < global.limit.large_size *1024 *1024) global.limit.cur_large--; transfer_reset(TRANS(upload), upload->segment->start); if (!upload_open_file(upload)) { send_safe(socket->fd, "FILE NOT FOUND", 0, strlen("FILE NOT FOUND")); socket_end(socket, S_IO); return 1; } upload_status_set(socket, S_UPLOADING); socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(upload_push_output), socket); #ifdef ADVANCED_CONNECTION socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(upload_get_advanced), socket); #endif return 1; } gint download_get_input(gpointer data, gint source, GdkInputCondition condition); gint server_send(gpointer data, gint source, GdkInputCondition condition); static void sockets_enable() { GList *dlist; socket_t *socket; upload_t *upload; transfer_t* trans; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket->data) continue; trans = TRANS(socket->data); if (socket->type == S_UPLOAD) { upload = socket->data; if (socket->output != -1) continue; if (trans->status != S_UPLOADING #ifdef ADVANCED_CONNECTION || upload->advanced == 2 #endif ) continue; socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(upload_push_output), socket); if (trans->user_info) trans->user_info->bytes[1] = 0; } else if (socket->type == S_SHARE) { if (socket->output != -1) continue; if (trans->status != S_UPLOADING) continue; socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(share_push_output), socket); if (trans->user_info) trans->user_info->bytes[1] = 0; } else if (socket->type == S_DOWNLOAD) { if (socket->input != -1) continue; if (trans->status != S_DOWNLOADING) continue; socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(download_get_input), socket); if (trans->user_info) trans->user_info->bytes[0] = 0; } else if (socket->type == S_SERVER) { net_t* net = socket->data; if (socket->fd < 0 || !net) continue; if (socket->output == -1 && net_has_outgoing(net)) socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(server_send), socket); } } global.up_width.bytes[0] = 0; // upload global.up_width.bytes[1] = 0; // server upload global.down_width.bytes[0] = 0; // download global.down_width.bytes[1] = 0; // server download } // thanks to Matthew Pratt for this code // I made a few changes.... GdkPixmap *transfer_draw_progress(GtkCList * clist, GdkPixmap * pixmap, long start, long pos, long stop, long size, int mark, int width) { int height; style_t *style1; style_t *style2; double percent1; double percent2; int w1, w2, h2; int pwidth = 0; int pheight = 0; int i1, i2; if (!GTK_WIDGET_REALIZED(clist)) gtk_widget_realize(GTK_WIDGET(clist)); style1 = style_get(global.scheme, "transfer_bar1"); style2 = style_get(global.scheme, "transfer_bar2"); if (!style1 || !style2) return NULL; height = clist->row_height; if (pixmap) gdk_window_get_size(pixmap, &pwidth, &pheight); if (!pixmap || (pwidth != width) || (pheight != height)) { if (pixmap) gdk_pixmap_unref(pixmap); pixmap = gdk_pixmap_new(global.win->window, width, height, -1); } if (pheight != height || !back0 || !back1 || !back2 || !trans_gc) transfer_init_colors(clist); // draw border gdk_gc_copy(trans_gc, GTK_WIDGET(clist)->style->black_gc); gdk_draw_rectangle(pixmap, trans_gc, TRUE, 0, 0, width, height); // draw the background (unfilled progress) for (i1 = 1; i1 < height-1; i1++) { if (i1 <= height/2) i2 = height/2-i1; else i2 = i1-height/2; gdk_gc_set_foreground(trans_gc, &back0[i2]); gdk_draw_rectangle(pixmap, trans_gc, TRUE, 1, i1, width - 2, 1); } // draw the actual progress bar // draw the lower/right white lines percent2 = (double)pos/(double)(stop-start); w2 = (int) ((width - 2) * percent2); if (w2 > 0) { // gdk_gc_copy(gc, GTK_WIDGET(clist)->style->white_gc); for (i1 = 1; i1 < height-1; i1++) { if (i1 <= height/2) i2 = height/2-i1; else i2 = i1-height/2; gdk_gc_set_foreground(trans_gc, &back1[i2]); gdk_draw_rectangle(pixmap, trans_gc, TRUE, 1, i1, w2, 1); } } if (start != 0 || stop != size) { h2 = (height-2)/2; percent1 = (double)start/(double)size; w1 = (int) ((width - 2) * percent1); percent2 = (double)(stop)/(double)size; w2 = (int) ((width - 2) * percent2); gdk_gc_copy(trans_gc, GTK_WIDGET(clist)->style->black_gc); gdk_draw_rectangle(pixmap, trans_gc, TRUE, w1, 0, w2-w1+2, h2+2); for (i1 = 1; i1 < h2+1; i1++) { if (i1*2 <= height/2) i2 = height/2-i1*2; else i2 = i1*2-height/2; gdk_gc_set_foreground(trans_gc, &back0[i2]); gdk_draw_rectangle(pixmap, trans_gc, TRUE, w1+1, i1, w2-w1, 1); } percent2 = (double)(start+pos)/(double)size; w2 = (int) ((width - 2) * percent2); if (w2 - w1 > 0) { // gdk_gc_copy(trans_gc, GTK_WIDGET(clist)->style->white_gc); for (i1 = 1; i1 < h2+1; i1++) { if (i1*2 <= height/2) i2 = height/2-i1*2; else i2 = i1*2-height/2; gdk_gc_set_foreground(trans_gc, &back2[i2]); gdk_draw_rectangle(pixmap, trans_gc, TRUE, w1+1, i1, w2-w1, 1); } } } if (mark) { gdk_gc_copy(trans_gc, GTK_WIDGET(clist)->style->black_gc); gdk_draw_rectangle(pixmap, trans_gc, TRUE, 0, height-height/3, height/3, height/3); } return pixmap; } GdkPixmap *resume_draw_progress(GtkCList * clist, GdkPixmap * pixmap, resume_t* resume, int width) { int height; // char text[128]; style_t *style1; style_t *style2; // GdkFont *font; file_segment_t* segment; GList* dlist; double percent1; double percent2; int w1, w2; int pwidth = 0; int pheight = 0; int i1, i2; GdkColor* backX; GdkFont* font; if (!GTK_WIDGET_REALIZED(clist)) gtk_widget_realize(GTK_WIDGET(clist)); style1 = style_get(global.scheme, "transfer_bar1"); style2 = style_get(global.scheme, "transfer_bar2"); if (!style1 || !style2) return NULL; height = clist->row_height; if (pixmap) gdk_window_get_size(pixmap, &pwidth, &pheight); if (!pixmap || (pwidth != width) || (pheight != height)) { if (pixmap) gdk_pixmap_unref(pixmap); pixmap = gdk_pixmap_new(global.win->window, width, height, -1); } if (pheight != height || !back0 || !back1 || !back2 || !trans_gc) transfer_init_colors(clist); // draw border gdk_gc_copy(trans_gc, GTK_WIDGET(clist)->style->black_gc); gdk_draw_rectangle(pixmap, trans_gc, TRUE, 0, 0, width, height); // draw the background (unfilled progress) for (i1 = 1; i1 < height-1; i1++) { if (i1 <= height/2) i2 = height/2-i1; else i2 = i1-height/2; gdk_gc_set_foreground(trans_gc, &back0[i2]); gdk_draw_rectangle(pixmap, trans_gc, TRUE, 1, i1, width - 2, 1); } // draw the actual progress bar if (resume->comp_size > 0) { int cnt = 0; for (dlist = resume->parts; dlist; dlist = dlist->next) { segment = dlist->data; if (segment->flags & PART_CHECK_ERROR) cnt++; percent1 = (double)segment->start/ (double)resume->comp_size; percent2 = (double)(segment->start+segment->size)/ (double)resume->comp_size; w1 = (int) ((width - 2) * percent1); w2 = (int) ((width - 2) * percent2); if (w2 - w1 > 0) { // gdk_gc_copy(trans_gc, GTK_WIDGET(clist)->style->white_gc); if (segment->socket) backX = back2; else backX = back1; for (i1 = 1; i1 < height-1; i1++) { if (i1 <= height/2) i2 = height/2-i1; else i2 = i1-height/2; gdk_gc_set_foreground(trans_gc, &backX[i2]); gdk_draw_rectangle(pixmap, trans_gc, TRUE, w1+1, i1, w2-w1, 1); } } } if (cnt > 0) { char text[128]; gdk_gc_set_foreground(trans_gc, style1->fore); strcpy(text, "Resume Error"); font = GTK_WIDGET(clist)->style->font; gdk_draw_text(pixmap, font, trans_gc, (width - gdk_string_width(font, text)) / 2, height - font->descent, text, strlen(text)); } } return pixmap; } void upload_update(socket_t * socket) { GtkCList *clist; int row; char str[200]; GdkPixmap *pixmap = NULL; GdkBitmap *bitmap = NULL; upload_t *upload; transfer_t* trans; file_segment_t* segment; if (!socket) return; upload = socket->data; trans = TRANS(upload); clist = GTK_CLIST(lookup_widget(global.win, "transfer_up")); row = gtk_clist_find_row_from_data(clist, socket); if (row < 0) return; strcpy(str, LineSpeed(trans->user_info->linespeed)); gtk_clist_set_text(clist, row, 4, str); // filesize if (upload->segment) sprintf(str, "%s [%.1f%%]", print_size(tstr[1], upload->segment->stop - upload->segment->start), (double)(upload->segment->size)*100/ (double)(upload->segment->stop - upload->segment->start)); else if (upload->file) sprintf(str, "%s", print_size(tstr[0], upload->file->size)); else *str = 0; gtk_clist_set_text(clist, row, 1, str); // status if (trans->status < 0 || trans->status >= S_NUMBER) { g_warning("upload_update(): invalid status %d", trans->status); return; } if (trans->status == S_WAITING) sprintf(str, "%d Waiting", (socket->max_cnt - socket->cnt)); else strcpy(str, status_names(trans->status)); gtk_clist_set_text(clist, row, 3, str); // progress if ((trans->status == S_UPLOADING) && (upload->segment)) { gtk_clist_get_pixmap(clist, row, 5, &pixmap, &bitmap); segment = upload->segment; pixmap = transfer_draw_progress(clist, pixmap, segment->start, segment->size, segment->stop, upload->file->size, upload->advanced, clist->column[5].width); gtk_clist_set_pixmap(clist, row, 5, pixmap, NULL); } else { gtk_clist_set_text(clist, row, 5, ""); } if (trans->rate > 0 || trans->status == S_UPLOADING) { print_speed(str, (int) trans->rate, 1); up_speed_pixs(trans->rate, &pixmap, &bitmap); gtk_clist_set_pixtext(clist, row, 6, str, 5, pixmap, bitmap); } else { gtk_clist_set_text(clist, row, 6, ""); } if (trans->rate > 0) { print_time_unit(str, trans->timeleft); } else if (trans->status == S_UPLOADING) { sprintf(str, "stalled"); } else { *str = 0; } gtk_clist_set_text(clist, row, 7, str); return; } void upload_remove_dead() { GList *dlist; GList *result1 = NULL; socket_t *socket; upload_t *upload; transfer_t* trans; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket || (socket->type != S_UPLOAD)) continue; upload = socket->data; trans = TRANS(upload); if (!upload) continue; if (trans->status != S_QUEUED) continue; if (trans->user_info->timestamp == 1) result1 = g_list_prepend(result1, socket); } for (dlist = result1; dlist; dlist = dlist->next) { socket = dlist->data; socket_end(socket, S_DELETE); } if (result1) g_list_free(result1); } download_t *download_new(file_t* file) { download_t *download; download = g_malloc(sizeof(download_t)); transfer_init(TRANS(download), S_QUEUED); download->file = file_duplicate(file); TRANS(download)->user_info = user_info_detect(file->net, file->user); TRANS(download)->user_info->linespeed = file->linespeed; download->nets = NULL; download_add_net(download, file->net, file->user); download->resume = NULL; download->queue = 0; download->csegment = NULL; download->fd = -1; download->node = NULL; #ifdef ADVANCED_CONNECTION download->advanced = 0; #endif return download; } void download_destroy(download_t *download) { if (!download) return; #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] destroying %p\n", download); #endif file_destroy(download->file); transfer_destroy(TRANS(download)); } void download_hide(socket_t * socket) { download_t *download; resume_t* resume; GtkCTreeNode *node; if (!socket) return; if (socket->type != S_DOWNLOAD) return; download = socket->data; if (!download) { g_warning("download_hide(): no download"); return; } resume = download->resume; if (!resume) return; if (resume->tree_no < 0 || !resume->node) return; node = download->node; if (!node) return; gtk_ctree_remove_node(DownloadTree[resume->tree_no], node); download->node = NULL; resume->needs_update = 1; } #ifdef ADVANCED_CONNECTION int download_send_start(socket_t* socket) { char str[1024]; int len1, len2; download_t *download = socket->data; file_segment_t* segment; segment = download->csegment->data; if (!segment) return 1; sprintf(str+4, "START %d", segment->start+segment->size); len1 = strlen(str+4); len2 = BSWAP32(len1); memcpy(str, &len2, 4); #ifdef TRANSFER_DEBUG printf("[ADVANCED] sending [%s]\n", str+4); #endif if (send_safe(socket->fd, str, len1+4, len1+4) != len1+4) { socket_end(socket, S_INCOMPLETE); return 0; } return 1; } int download_send_stop(socket_t* socket) { char str[1024]; int len1, len2; download_t *download = socket->data; file_segment_t* segment; segment = download->csegment->data; if (!segment) return 1; if (download->csegment->next) { len1 = segment->stop + RESUME_CHECK_LENGTH; } else { len1 = segment->stop; } sprintf(str+4, "STOP %d", len1); len1 = strlen(str+4); len2 = BSWAP32(len1); memcpy(str, &len2, 4); #ifdef TRANSFER_DEBUG printf("[ADVANCED] sending [%s]\n", str+4); #endif if (send_safe(socket->fd, str, len1+4, len1+4) != len1+4) { socket_end(socket, S_INCOMPLETE); return 0; } return 1; } int download_send_finish(socket_t* socket) { char str[1024]; int len1, len2; sprintf(str+4, "FINISHED"); len1 = strlen(str+4); len2 = BSWAP32(len1); memcpy(str, &len2, 4); #ifdef TRANSFER_DEBUG printf("[ADVANCED] sending [%s]\n", str+4); #endif if (send_safe(socket->fd, str, len1+4, len1+4) != len1+4) { socket_end(socket, S_INCOMPLETE); return 0; } return 1; } #endif void download_status_set(socket_t* socket, int status) { download_t *download; int add; double val; char str[1024]; chat_page_t *page; file_segment_t* segment; transfer_t* trans; if (!socket) return; download = socket->data; if (!download) return; trans = TRANS(download); add = transfer_status_dist(trans->status, status); #ifdef TRANSFER_DEBUG // printf("[DOWNLOAD] status change %d -> %d\n", trans->status, status); #endif trans->user_info->cur[0] += add; global.limit.cur_downloads += add; if (global.limit.cur_downloads == 0) resume_saver_stop(); else resume_saver_start(); if (status == S_DOWNLOADING) { command_send(NULL, CMD_DOWNLOAD_START); global.limit.cur_real_downloads++; trans->user_info->real_cur[0]++; trans->start_time = global.current_time; trans->transferred = 0; if (global.limit.cur_real_downloads == 1) ext_handle(EVENT_FIRST_DOWNLOAD, trans->user_info->nick, download->resume->filename); ext_handle(EVENT_DOWNLOAD_START, trans->user_info->nick, download->resume->filename); check_uploads_again(); } if (trans->status == S_DOWNLOADING) { command_send(NULL, CMD_DOWNLOAD_END); global.limit.cur_real_downloads--; trans->user_info->real_cur[0]--; trans->stop_time = global.current_time; check_uploads_again(); if (global.limit.cur_real_downloads == 0) ext_handle(EVENT_LAST_DOWNLOAD, trans->user_info->nick, download->resume->filename); } // test that allows only to request x files if remotely queued if (status == S_REMOTE) trans->user_info->remotes++; if (trans->status == S_REMOTE) trans->user_info->remotes--; segment = download->csegment?download->csegment->data:NULL; if (status == S_DOWNLOADING) { resume_t* resume = download->resume; resume->last_access = global.current_time; l_log(NULL, "downloads", LOG_OTHER, "Downloading [%s] from [%s]%s at [%ld]\n", download->file->filename, trans->user_info->nick, trans->is_dcc ? " (DCC)" : "", segment->start); if ((global.options.no_piping & NOPIPE_DOWNLOAD) == 0) { char str1[100]; char str2[100]; if (global.options.piping & PIPE_DOWNLOAD) { page = chat_page_search(NULL, "Downloads", P_OTHER, 3); if (!page) page = create_other_page(NULL, "Downloads", "Downloads"); } else { page = chat_page_get_printable(); } sprintf(str1, "%d", segment->start); sprintf(str2, "%d", segment->stop); print_transfer_prefix(page, 1, str1, str2, DL_GET_NICK(download), DL_GET_NET(download), download->file->longname, download->file->filename, NULL, NULL); } } else if (status == S_FINISHED) { segment = download->resume->parts?download->resume->parts->data:NULL; l_log(NULL, "downloads", LOG_OTHER, "Finished [%s] : %d segments total\n", download->file->filename, segment?segment->merge_cnt+1:0); if ((global.options.no_piping & NOPIPE_DOWNLOAD) == 0) { if (global.options.piping & PIPE_DOWNLOAD) { page = chat_page_search(NULL, "Downloads", P_OTHER, 3); if (!page) page = create_other_page(NULL, "Downloads", "Downloads"); } else { page = chat_page_get_printable(); } sprintf(str, "%d segments", segment?segment->merge_cnt+1:0); print_transfer_prefix(page, 1, status_names(status), str, DL_GET_NICK(download), DL_GET_NET(download), download->file->longname, download->file->filename, NULL, NULL); } } else if (trans->status == S_DOWNLOADING) { if (trans->stop_time - trans->start_time > 0) val = trans->transferred / (trans->stop_time - trans->start_time); else val = 0; print_speed(str, val, 1); l_log(NULL, "downloads", LOG_OTHER, "Ending [%s] from [%s]%s :%s: [%ld] (%s)\n", download->file->filename, trans->user_info->nick, trans->is_dcc ? " (DCC)" : "", status_names(status), trans->transferred, str); if ((global.options.no_piping & NOPIPE_DOWNLOAD) == 0) { if (global.options.piping & PIPE_DOWNLOAD) { page = chat_page_search(NULL, "Downloads", P_OTHER, 3); if (!page) page = create_other_page(NULL, "Downloads", "Downloads"); } else { page = chat_page_get_printable(); } print_transfer_prefix(page, 1, status_names(status), str, DL_GET_NICK(download), DL_GET_NET(download), download->file->longname, download->file->filename, NULL, NULL); } } trans->status = status; trans->needs_update = 1; if (add != 0) download->resume->needs_update = 1; } static void downloads_update() { int temp; GtkCTree* ctree; GtkCTreeNode* node; resume_t* resume; GList* dlist; socket_t* socket; transfer_t* trans; for (temp = 0; temp < 4; temp++) { ctree = DownloadTree[temp]; gtk_clist_freeze(GTK_CLIST(ctree)); node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list); while (node) { resume = gtk_ctree_node_get_row_data(ctree, node); node = GTK_CTREE_ROW (node)->sibling; if (resume->needs_update) resume_update(resume); dlist = resume->downloads; while (dlist) { socket = dlist->data; dlist = dlist->next; trans = TRANS(socket->data); if (trans->needs_update) download_update(socket); } } gtk_clist_thaw(GTK_CLIST(ctree)); } } net_user_t* download_find_net_user(download_t* download, net_t* net, char* user); socket_t *download_search_mapable(net_t* net, char *user, char *winname) { socket_t *socket; download_t *download; GList *dlist; transfer_t* trans; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (socket->type != S_DOWNLOAD) continue; download = socket->data; if (!download) continue; trans = TRANS(download); if (!g_strcasecmp(download->file->winname, winname) && (!net || download_find_net_user(download, net, user)) && (!transfer_in_progress(trans) || trans->status == S_WAITING) && (trans->status != S_FINISHED)) return socket; } return NULL; } int download_to_destroy(socket_t * socket, int mode ATTR_UNUSED) { download_t* download = socket->data; if (!download->nets) return 1; else return 0; } int download_to_retry(download_t* download, int mode) { switch (mode) { case S_TIMEOUT: if (global.options.auto_retry & RETRY_TIMEOUT) return global.options.retry_timeout[0] * 1000; break; case S_REJECT: if (global.options.auto_retry & RETRY_REJECT) return global.options.retry_timeout[1] * 1000; break; case S_INCOMPLETE: if (global.options.auto_retry & RETRY_INCOMPLETE) return global.options.retry_timeout[2] * 1000; break; case S_CONERROR: if (global.options.auto_retry & RETRY_CONERROR) return global.options.retry_timeout[3] * 1000; break; case S_REMOTE: if (download->queue >= 10000) { download->queue -= 9999; // adjust the value to the real one return 10 * 1000; } else if (global.options.auto_retry & RETRY_REMOTE) return global.options.retry_timeout[4] * 1000; break; case S_UNAVAILABLE: return 1000; break; } return -1; } int download_grab_resume(socket_t * socket, resume_t * resume) { download_t *download = socket->data; long stop; file_segment_t* segment; download->resume = resume; if ((resume->flags & RESUME_FREE_SEGMENT) == 0) return 0; if (resume->active > 0 && (resume->flags & RESUME_DONT_MSOURCE)) return 0; segment = file_segment_find_free(resume, &stop); if (stop == 0) { #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] could not grab resume: no free segment\n"); #endif return 0; } return 1; } static resume_t* create_resume(file_t* file, int dcc) { struct stat st; resume_t *resume; char *filename; char* f2; file_segment_t* segment; #ifdef RESUME_DEBUG printf("[RESUME] creating [%s]\n", file->longname); #endif filename = g_strdup_printf("%s%c%s", global.incomplete_path, DIR_SEP, file->filename); convert_local_name(filename); while (resume_search_long_file(filename)) { // resume entry already exists, renaming f2 = rename_file(filename); if (!f2) return NULL; filename = f2; } resume = resume_new(global.current_time); resume->filename = filename; resume->comp_size = file->size; resume->is_dcc = dcc; // if file exists on disc use it! could be dangerous. if (stat(filename, &st) >= 0) { segment = file_segment_new(0, st.st_size); resume->parts = g_list_prepend(resume->parts, segment); segment->size = st.st_size; resume->inc_size = st.st_size; } resume_show(resume); if (!dcc) resume_save(NULL); return resume; } int download_search_queued(resume_t * resume) { GList *dlist; socket_t *socket; download_t *download; int result = 0; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (socket->type != S_DOWNLOAD) continue; download = socket->data; if (!download) continue; if (download->resume == resume && TRANS(download)->status == S_QUEUED) result++; } return result; } void download_update_download(socket_t * socket) { GtkCTree *ctree; GtkCTreeNode *node; char str[200]; GdkPixmap *pixmap = NULL; GdkBitmap *bitmap = NULL; download_t *download; transfer_t* trans; file_segment_t* segment; net_t* net; if (!socket) return; download = socket->data; trans = TRANS(download); if (!download->resume) return; node = download->resume->node; if (download->resume->tree_no < 0 || !node) return; ctree = DownloadTree[download->resume->tree_no]; node = download->node; if (!node) return; // col 0: filename -> skip // col 1: filesize if (download->csegment) { segment = download->csegment->data; sprintf(str, "%s [%.1f%%]", print_size(tstr[1], segment->stop - segment->start), (double)(segment->size)*100/ (double)(segment->stop - segment->start)); } else { *str = 0; } gtk_ctree_node_set_text(ctree, node, 1, str); net = DL_GET_NET(download); sprintf(str, "[%s] %s", net?NetType[net->type]:"?", trans->user_info->nick); gtk_ctree_node_set_text(ctree, node, 2, str); // col 2: user -> skip // col 3: speed gtk_ctree_node_set_text(ctree, node, 3, LineSpeed(trans->user_info->linespeed)); // col 4: status/progress if ((trans->status < 0) || (trans->status >= S_NUMBER)) { g_warning("download_update: invalid status %d", trans->status); return; } if ((trans->status == S_DOWNLOADING) && (download->csegment)) { segment = download->csegment->data; gtk_ctree_node_get_pixmap(ctree, node, 4, &pixmap, &bitmap); pixmap = transfer_draw_progress(GTK_CLIST(ctree), pixmap, segment->start, segment->size, segment->stop, download->resume->comp_size, download->advanced, GTK_CLIST(ctree)->column[4].width); gtk_ctree_node_set_pixmap(ctree, node, 4, pixmap, NULL); } else { if (trans->status == S_WAITING) { sprintf(str, "%d Waiting", (socket->max_cnt - socket->cnt)); } else if (trans->status == S_REMOTE) { sprintf(str, "%d Remotely queued", download->queue); } else { strcpy(str, status_names(trans->status)); } if (socket->timer >= 0) { strcat(str, " "); strcat(str, "[retry]"); } gtk_ctree_node_set_text(ctree, node, 4, str); } // col 5: rate if (trans->rate > 0 || trans->status == S_DOWNLOADING) { print_speed(str, (int) trans->rate, 1); down_speed_pixs(trans->rate, &pixmap, &bitmap); gtk_ctree_node_set_pixtext(ctree, node, 5, str, 5, pixmap, bitmap); } else { gtk_ctree_node_set_text(ctree, node, 5, ""); } // col 6: timeleft if (trans->rate > 0) { print_time_unit(str, trans->timeleft); } else if (trans->status == S_DOWNLOADING) { sprintf(str, "stalled"); } else { *str = 0; } gtk_ctree_node_set_text(ctree, node, 6, str); return; } void download_update_resume(socket_t * socket) { GtkCTree *ctree; GtkCTreeNode *node; char str[200]; download_t *download; transfer_t* trans; net_t* net; if (!socket) return; download = socket->data; trans = TRANS(download); if (!download->resume) return; node = download->resume->node; if (download->resume->tree_no < 0 || !node) return; ctree = DownloadTree[download->resume->tree_no]; node = download->node; if (!node) return; // col 0: filename -> skip // col 1: filesize if (download->csegment) { file_segment_t* segment = download->csegment->data; sprintf(str, "%s [%.1f%%]", print_size(tstr[1], segment->stop - segment->start), (double)(segment->size)*100/ (double)(segment->stop - segment->start)); } else { *str = 0; } gtk_ctree_node_set_text(ctree, node, 1, str); // col 2: user net = DL_GET_NET(download); sprintf(str, "[%s] %s", net?NetType[net->type]:"?", trans->user_info->nick); gtk_ctree_node_set_text(ctree, node, 2, str); // col 3: status if (trans->status == S_DOWNLOADING && download->csegment) { GdkPixmap *pixmap = NULL; GdkBitmap *bitmap = NULL; file_segment_t* segment; segment = download->csegment->data; gtk_ctree_node_get_pixmap(ctree, node, 3, &pixmap, &bitmap); pixmap = transfer_draw_progress(GTK_CLIST(ctree), pixmap, segment->start, segment->size, segment->stop, download->resume->comp_size, download->advanced, GTK_CLIST(ctree)->column[3].width); gtk_ctree_node_set_pixmap(ctree, node, 3, pixmap, NULL); } else { if (trans->status == S_WAITING) sprintf(str, "%d Waiting", (socket->max_cnt - socket->cnt)); else if (trans->status == S_REMOTE) sprintf(str, "%d Remotely queued", download->queue); else strcpy(str, status_names(trans->status)); if (socket->timer >= 0) { strcat(str, " "); strcat(str, "[retry]"); } gtk_ctree_node_set_text(ctree, node, 3, str); } return; } void download_update(socket_t * socket) { download_t *download; resume_t* resume; if (!socket) return; download = socket->data; if (!download || !download->resume) return; resume = download->resume; if (resume->tree_no < 0 || !resume->node) return; if (resume->tree_no == 0) { download_update_download(socket); } else { download_update_resume(socket); } TRANS(download)->needs_update = 0; return; } socket_t *download_create(file_t * file, resume_t* resume, char* search, char* dir, int dcc) { download_t *new_trans; socket_t *socket; GList* dlist; // only test for existing transfer, if it should be mapped to an existing resume if (resume) { // just do nothing if file is not online if (!NET_CONNECTED(file->net)) return NULL; for (dlist = resume->downloads; dlist; dlist = dlist->next) { socket = dlist->data; new_trans = socket->data; if (!new_trans) continue; /* if (!strcmp(new_trans->winname, file->winname) && !g_strcasecmp(new_trans->data->user_info->nick, nick)) { */ if (!strcmp(new_trans->file->winname, file->winname)) { if (download_find_net_user(new_trans, file->net, file->user)) { socket->ip_long = file->ip; return socket; } else if (socket->ip_long == file->ip) { download_add_net(new_trans, file->net, file->user); if (g_list_length(new_trans->nets) == 1) TRANS(new_trans)->needs_update = 1; if (transfer_in_progress(TRANS(new_trans))) return NULL; return socket; } } } } else { resume = create_resume(file, dcc); if (search) resume->search_string = g_strdup(search); if (dir) resume->dirname = g_strdup(dir); } if (!NET_CONNECTED(file->net)) return NULL; new_trans = download_new(file); TRANS(new_trans)->is_dcc = dcc; new_trans->resume = resume; socket = socket_new(S_DOWNLOAD); socket->data = new_trans; socket->ip_long = file->ip; resume->downloads = g_list_prepend(resume->downloads, socket); download_show(socket); return socket; } void download_file(file_t * file, char* search_string, char* dir) { GList* result; file_t* file2; file_t* file3; GtkCTree* ctree; GtkCTreeNode* node1; GtkCTreeNode* node2; GList* dlist; if (!global.options.check_lib_for_download) { download_file_without_check(file, search_string, dir); return; } result = file_tree_search_filesize(FILE_TREE(global.lib), file); if (!result) { download_file_without_check(file, search_string, dir); return; } if (global.queue_win) { gtk_widget_show(global.queue_win); if (global.queue_win->window) gdk_window_raise(global.queue_win->window); } else { global.queue_win = create_queue_win(); gtk_widget_show(global.queue_win); } file2 = file_duplicate(file); ctree = GTK_CTREE(lookup_widget(global.queue_win, "ctree6")); strcpy(tstr[0], file2->filename); strcpy(tstr[1], file2->user); sprintf(tstr[2], "%lu", file2->size); node1 = gtk_ctree_insert_node(ctree, NULL, NULL, list, 5, NULL, NULL, NULL, NULL, FALSE, FALSE); gtk_ctree_node_set_row_data_full(ctree, node1, file2, (GtkDestroyNotify)file_destroy); for (dlist = result; dlist; dlist = dlist->next) { file3 = dlist->data; strcpy(tstr[0], file3->shortname); strcpy(tstr[1], "local"); sprintf(tstr[2], "%lu", file3->size); node2 = gtk_ctree_insert_node(ctree, node1, NULL, list, 5, NULL, NULL, NULL, NULL, FALSE, FALSE); } } void download_file_without_check(file_t* file, char* search, char* dir) { socket_t *socket; socket = download_create(file, NULL, search, dir, 0); if (socket) download_start(socket, FALSE); } int download_real_allowed() { if (global.limit.max_downloads > 0 && global.limit.max_downloads <= global.limit.cur_real_downloads) return 0; else return 1; } static int download_allowed(socket_t * socket) { download_t *download = socket->data; transfer_t* trans = TRANS(download); int add = transfer_status_dist(trans->status, S_QUEUED); int add2 = -(trans->status == S_REMOTE); user_info_t* userinfo; int limit; if (global.status.exiting == E_SAFE) return 0; if (download->resume->active > 0 && (download->resume->flags & RESUME_DONT_MSOURCE)) return 0; if (download->resume->flags & RESUME_INACTIVE) return 0; userinfo = trans->user_info; if (userinfo->max[0] == -1) // default limit limit = global.limit.default_downloads; else limit = userinfo->max[0]; // only try one at a time from old winmx users if ((userinfo->client == C_WINMX_26) && (userinfo->cur[0] + add + userinfo->remotes + add2 >= 1)) return 0; if (string_list_search(LIST_NODOWNLOAD, trans->user_info->nick)) return 0; if (limit == 0) return 1; // ok, we have limit > 0 if (userinfo->cur[0] + add + userinfo->remotes + add2 >= limit) return 0; return download_real_allowed(); } void download_show(socket_t * socket) { download_t *download = socket->data; transfer_t* trans = TRANS(download); resume_t* resume = download->resume; GtkCTreeNode *node; net_t* net; if (!resume) return; if (resume->tree_no < 0 || !resume->node) return; strcpy(tstr[0], download->file->filename); net = DL_GET_NET(download); sprintf(tstr[2], "[%s] %s", net?NetType[net->type]:"?", trans->user_info->nick); tstr[1][0] = tstr[3][0] = tstr[4][0] = tstr[5][0] = tstr[6][0] = 0; node = gtk_ctree_insert_node(DownloadTree[resume->tree_no], resume->node, NULL, list, 5, NULL, NULL, NULL, NULL, FALSE, FALSE); download->node = node; gtk_ctree_node_set_row_data(DownloadTree[resume->tree_no], node, (gpointer) socket); download_update(socket); } void download_start(socket_t * socket, int force) { download_t *download = socket->data; transfer_t* trans = TRANS(download); net_t* net; char* user; if (trans->is_dcc) force = 1; // removing timeout if set if (socket->timer >= 0) { gtk_timeout_remove(socket->timer); socket->timer = -1; } net = DL_GET_NET(download); user = DL_GET_NICK(download); if (!NET_CONNECTED(net)) { // server is not online // FIXME! Lopster (sometimes?) crashes after this point // !!Check whether net is still in net list (valid pointer?) socket_end(socket, S_UNAVAILABLE); return; } // update the userinfo // MUST be done AFTER the NET_ONLINE/NET_CONNECTED check user_info_get(trans->user_info, net); if (!force) { if (!download_allowed(socket)) { socket_end(socket, S_QUEUED); return; } } if (download->resume->comp_size && download->resume->comp_size != download->file->size) { g_warning("download_start(): size compare %ld %ld [%s]", download->resume->comp_size, download->file->size, download->file->filename); } if (resume_finished(download->resume)) { // this might happen, if the user modifies the size of the resume entry socket_end(socket, S_PART); return; } // trying to grab if (!download_grab_resume(socket, download->resume)) { socket_end(socket, S_QUEUED); return; } trans->hist_cnt = 0; socket->cnt = 0; socket->max_cnt = global.network.transfer_timeout_down; // now starting the download if (trans->is_dcc) { transfer_connect_and_start(socket); } else { #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] requesting [%s][%s]\n", download->file->filename, download->file->user); #endif if (!(net->flags & NETWORK_NO_WINMX) && (trans->user_info->client == C_WINMX_26)) { send_notice(net, user, "//WantQueue", 0); } command_send(net, CMD_DOWNLOAD, user, download->file->winname); download_status_set(socket, S_WAITING); } } int download_open_file(download_t *download) { resume_t *resume; file_segment_t* segment; if (!download->resume) { g_warning("download_open_file(): ops, no resume"); return -1; } resume = download->resume; segment = download->csegment->data; #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] opening [%s]\n", resume->filename); #endif download->fd = open(resume->filename, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (download->fd == -1) { g_warning("download_open_file(): could not open file [%s]", resume->filename); } else { #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] seeking to %d %d\n", segment->start, segment->size); #endif if (lseek(download->fd, segment->start+segment->size, SEEK_SET) == (off_t)-1) { g_warning("download_open_file(): error when seeking"); close(download->fd); download->fd = -1; } } return download->fd; } static void download_finish_segment(download_t* download) { resume_t* resume = download->resume; transfer_t* trans = TRANS(download); file_segment_t* segment; int segment_done = 0; // now there could be a free segment again resume->flags |= RESUME_FREE_SEGMENT; segment = download->csegment->data; if (segment->size >= segment->stop - segment->start) { segment->size = segment->stop - segment->start; segment_done = 1; } segment->socket = NULL; if (!segment_done && segment->size <= 10*RESUME_CHECK_LENGTH) { file_segment_remove(download->resume, segment); trans->timeleft = 0; trans->rate = 0; } else { trans->timeleft = trans->stop_time - trans->start_time; if (trans->timeleft > 0) trans->rate = trans->transferred / trans->timeleft; else trans->rate = 0; file_segment_merge(resume, download->csegment); } download->csegment = NULL; if (resume->active > 0) { resume->active--; resume->needs_update = 1; } } void download_end(socket_t * socket, int mode) { download_t *download = socket->data; transfer_t* trans = TRANS(download); resume_t *resume; char* download_dir; int mime; const char* folder; char* command; char* pos; struct stat st; net_user_t* nu; if (!download) return; #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] ending (mode %d) [%s][%s]\n", mode, download->file->filename, trans->user_info->nick); #endif trans->stop_time = global.current_time; resume = download->resume; // return if download is not linked to resume // (should never be) if (!resume) { g_warning("download_end(): no resume found"); return; } if (download->fd >= 0) { close(download->fd); download->fd = -1; } download_status_set(socket, mode); if (download->csegment) download_finish_segment(download); trans->needs_update = 1; switch (mode) { case S_PART: if (resume_finished(resume)) { resume->flags |= RESUME_FINISHED; download_status_set(socket, S_FINISHED); mime = mtype_get(download->resume->filename); folder = mtype_get_download(mime); if (!folder || *folder == 0) { // fallback to default folder folder = mtype_get_download(MEDIA_NONE); } if (resume->dirname && resume->dirname[0]) { if (resume->dirname[0] == DIR_SEP || (resume->dirname[1] == ':' && resume->dirname[2] == '\\')) // drive letter download_dir = g_strdup(resume->dirname); else if (folder && (*folder)) download_dir = g_strdup_printf("%s%c%s", folder, DIR_SEP, resume->dirname); else download_dir = g_strdup_printf(".%c%s", DIR_SEP, resume->dirname); } else { if (folder && (*folder)) download_dir = g_strdup(folder); else download_dir = g_strdup("."); } if (strcmp(download_dir, global.incomplete_path)) { create_dir(download_dir); command = g_strdup_printf("%s%c%s", download_dir, DIR_SEP, get_file_name(resume->filename)); if (stat(command, &st) >= 0) { pos = rename_file(command); } else pos = command; file_move(resume->filename, pos); g_free(resume->filename); resume->filename = g_strdup(pos); g_free(pos); } else { #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] dont move: source and destination are the same\n"); #endif } ext_handle(EVENT_DL_FINISHED, trans->user_info->nick, resume->filename); g_free(download_dir); } resume->needs_update = 1; resume_save(NULL); break; case S_TIMEOUT: nu = download->nets?download->nets->data:NULL; if (nu) { download->nets = g_list_remove(download->nets, nu); download->nets = g_list_append(download->nets, nu); } resume->needs_update = 1; break; case S_UNAVAILABLE: nu = download->nets?download->nets->data:NULL; if (nu) { download->nets = g_list_remove(download->nets, nu); g_free(nu->user); g_free(nu); } resume->needs_update = 1; break; case S_FINISHED: case S_IO: case S_RESUME_ERR: case S_DELETE: case S_INCOMPLETE: case S_CANCELED: resume->needs_update = 1; break; case S_QUEUED: case S_REMOTE: default: break; } if (resume->flags & RESUME_FINISHED) resume_cancel(resume); } #define MAX_GET 20240 long download_calc_max(socket_t* socket) { long m1; long m2; long limit; download_t* download = socket->data; transfer_t* trans = TRANS(download); user_info_t* userinfo; static int warned = 0; long dlimit; userinfo = trans->user_info; if (global.up_width.limit < 5*1024 && server_get_highest_level() < L_MOD) { if (!warned) { info_dialog("Your download bandwidth limit will be restricted to twice\nyour upload bandwidth limit unless you set it >= 5kB/s"); warned = 1; } dlimit = 2*global.up_width.limit; } else { dlimit = global.down_width.limit; } if (userinfo->limit[0]) { if (userinfo->limit[0] <= userinfo->bytes[0]) { gdk_input_remove(socket->input); socket->input = -1; return 0; } else { m1 = userinfo->limit[0] - userinfo->bytes[0]; } } else m1 = MAX_GET; if (userinfo->ignore_global[0]) { m2 = MAX_GET; } else if (global.down_width.bytes[0] >= dlimit) { downloads_disable(); return 0; } else { m2 = dlimit - global.down_width.bytes[0]; } if (m1 > m2) m1 = m2; if (global.limit.cur_real_downloads <= 0) { g_warning("cur_real_downloads shouldnt be <= 0"); limit = dlimit/4; } else { limit = dlimit/global.limit.cur_real_downloads/4; } if (limit > MAX_GET) limit = MAX_GET; if (m1 > limit) m1 = limit; return m1; } #ifdef ADVANCED_CONNECTION int download_renew(socket_t* socket) { download_t* download = socket->data; resume_t* resume = download->resume; long stop; file_segment_t* segment; if (!download_grab_resume(socket, resume)) { download_send_finish(socket); return 0; } download_finish_segment(download); // now find a new segment segment = file_segment_find_free(download->resume, &stop); if (!stop) { download_send_finish(socket); return 0; } segment = file_segment_create_after(download->resume, segment, stop); if (!segment) { download_send_finish(socket); return 0; } file_segment_attach_to_download(socket, segment); // seek to the new position #ifdef TRANSFER_DEBUG printf("[ADVANCED] seeking to %d %d\n", segment->start, segment->size); #endif if (lseek(download->fd, segment->start+segment->size, SEEK_SET) == (off_t)-1) { printf("*** [ADVANCED] error when seeking to %d %d\n", segment->start, segment->size); download_send_finish(socket); socket_end(socket, S_IO); return 1; } download->advanced = 2; #ifdef TRANSFER_DEBUG printf("[ADVANCED] sending new start and stop position\n"); #endif if (!download_send_start(socket)) return 1; if (!download_send_stop(socket)) return 1; // download_status_set(socket, S_INFO); return 1; } #endif gint download_get_input(gpointer data, gint source, GdkInputCondition condition) { char buf[MAX_GET + 1]; char buf2[128]; int n, n2, n3; socket_t *socket = (socket_t *) data; download_t *download = socket->data; transfer_t* trans = TRANS(download); long maxget; file_segment_t* segment; file_segment_t* segment2; long real_stop; if (condition != GDK_INPUT_READ) { socket_end(socket, S_INCOMPLETE); return 1; } segment = download->csegment->data; // check the stop position and adjust it if neccessary... if (download->csegment->next) { segment2 = download->csegment->next->data; if (segment->stop != segment2->start) { segment->stop = segment2->start; #ifdef ADVANCED_CONNECTION if (download->advanced == 1) download_send_stop(socket); #endif } real_stop = segment->stop + RESUME_CHECK_LENGTH; } else { if (download->resume->comp_size && segment->stop != download->resume->comp_size) { segment->stop = download->resume->comp_size; #ifdef ADVANCED_CONNECTION if (download->advanced == 1) download_send_stop(socket); #endif } real_stop = segment->stop; } #ifdef ADVANCED_CONNECTION if (download->advanced == 2) { maxget = 9; } else { #endif // calc how many bytes we like to receive maxget = download_calc_max(socket); if (!maxget) { // disable the download gdk_input_remove(socket->input); socket->input = -1; return 1; } if (maxget > real_stop - segment->start - segment->size) maxget = real_stop - segment->start - segment->size; #ifdef ADVANCED_CONNECTION } #endif // now receive.. n = recv(source, buf, maxget, 0); if (n <= 0) { #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] failed to read %ld bytes (%s) %d\n", maxget, strerror(errno), n); #endif // maxget always should be > 0 so, we dont have the part finished, // -> its incomplete socket_end(socket, S_INCOMPLETE); return 0; } else { buf[n] = 0; } #ifdef ADVANCED_CONNECTION if (download->advanced == 2) { if (strcmp(buf, "CONTINUED")) { #ifdef TRANSFER_DEBUG printf("[ADVANCED] other client is not advanced, giving up :(\n"); #endif socket_end(socket, S_INCOMPLETE); } else { #ifdef TRANSFER_DEBUG printf("[ADVANCED] we really have an advanced connection :)\n"); #endif download->advanced = 1; } return 0; } #endif // do some statistic stuff global.down_width.bytes[0] += n; trans->user_info->bytes[0] += n; trans->transferred += n; socket->cnt = 0; // if we are at segment start, it might be a // FILE NOT FOUND or FILE NOT SHARED or something. if ((segment->size <= 0) && !strncasecmp(buf, "FILE NOT", 8)) { buf[n] = 0; #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] got [%s]\n", buf); #endif socket_end(socket, S_UNAVAILABLE); return 0; } else { // now handle the read data n2 = n3 = 0; // first do the resume check at the beginning. if (segment->size < 0) { // calc how many bytes we can use for resume check if (-segment->size > n) n2 = n; else n2 = -segment->size; #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] resume check: checking %d bytes\n", n2); #endif // load data for resume check. if (read(download->fd, buf2, n2) != n2) { #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] could not read end of segment for resume check (%d bytes)\n", n2); #endif socket_end(socket, S_IO); return 0; } // now do the resume check of n2 bytes data if (memcmp(buf2, buf, n2) != 0) { #ifdef TRANSFER_DEBUG int i1; printf("[DOWNLOAD] resume check of %d bytes failed\n", n2); for (i1 = 0; i1 < n2; i1++) { printf("\t%3d: %3d %3d\n", i1, buf2[i1], buf[i1]); } #endif if (download->csegment->prev) { segment2 = download->csegment->prev->data; segment2->flags |= PART_CHECK_ERROR; } socket_end(socket, S_RESUME_ERR); return 0; } // ok, resume check passed, now decrease the number of bytes // that are left for writing..(Note: n2 is always <= n) n -= n2; segment->size += n2; // update file info if we dont know the complete size but // only if we did the whole resume check (segment->size == 0) if (segment->size == 0) { if (download->resume->comp_size == 0) resume_set_size(download->resume, download->file->size); if (download->csegment->prev) { segment2 = download->csegment->prev->data; segment2->flags &= ~PART_CHECK_ERROR; } } // return if no data left... if (n == 0) return 0; } // ok, n bytes left to write from buffer position n2, but // at most to position segment->stop (we might have received // the data to real_stop) if (segment->start+segment->size+n > segment->stop) { n3 = segment->stop - segment->start - segment->size; // if we already wrote the whole segment we dont write any data if (n3 < 0) n3 = 0; } else { // write all the data. n3 = n; } // now writing n3 bytes... if (n3 > 0) { if ((write(download->fd, buf+n2, n3)) != n3) { g_warning("download_get_input(): could not write to file [%d][%d]\n", n2, n3); socket_end(socket, S_IO); return 0; } segment->size += n3; download->resume->inc_size += n3; n -= n3; } // ok, n bytes left for resume check at segment end // buffer pos is now n2+n3 // there _is_ a next segment! if there wasnt then n wouldnt // exceed segment->stop and n would be 0 now (see real_stop) if (n > 0) { // n should now be at max RESUME_CHECK_LENGTH #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] resume end check: checking %d bytes\n", n); #endif // load data for resume check. if (read(download->fd, buf2, n) != n) { g_warning("download_get_input(): could not read start of segment (%d bytes)\n", n); socket_end(socket, S_RESUME_ERR); return 0; } // now do the resume check of n bytes data if (memcmp(buf2, buf+n2+n3, n) != 0) { #ifdef TRANSFER_DEBUG int i1; g_warning("[DOWNLOAD] resume check of %d bytes failed\n", n); for (i1 = 0; i1 < n; i1++) { printf("\t%3d: %3d %3d\n", i1, buf2[i1], buf[n2+n3+i1]); } #endif // dont delete the whole downloaded segment now, just // set the error flag. segment->flags |= PART_CHECK_ERROR; socket_end(socket, S_RESUME_ERR); return 0; } segment->size += n; } // probably finish the segment if (segment->start+segment->size >= real_stop) { segment->flags &= ~PART_CHECK_ERROR; // resume check passed #ifdef ADVANCED_CONNECTION if (download->advanced == 1) { if (!download_renew(socket)) socket_end(socket, S_PART); } else #endif socket_end(socket, S_PART); } } return 0; } gint download_fw_get_info(gpointer data, gint source, GdkInputCondition condition) { #ifndef HAVE_LIBLCONV_H char buffer[1025]; #else char buffer[2047]; char lconv_buf[2047]; #endif int cnt; socket_t *socket = (socket_t *) data; socket_t *socket2; char *username; char *filename; char *size; download_t *download; transfer_t *trans; char *temp_str; long lsize; file_segment_t* segment; long stop; resume_t* resume; if (condition != GDK_INPUT_READ) { socket_destroy(socket, 0); return 1; } gdk_input_remove(socket->input); socket->input = -1; cnt = 0; switch (cnt = recv(source, buffer, 1024, 0)) { case -1: case 0: socket_destroy(socket, 0); return 1; default: break; } buffer[cnt] = 0; #ifdef HAVE_LIBLCONV_H if (global.options.use_iconv) { lconv_conv(LCONV_SPEC, local_codeset, global.options.dest_codeset, lconv_buf, buffer); strcpy(buffer, lconv_buf); } #endif #ifdef TRANSFER_DEBUG // printf("download_info [%s]\n", buffer); #endif username = arg(buffer, 0); filename = arg(NULL, 0); size = arg(NULL, 0); if (!size) { socket_destroy(socket, 0); return 1; } #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] firewall info [%s][%s][%s]\n", username, filename, size); #endif socket2 = download_search_mapable(NULL, username, filename); if (!socket2) { socket_destroy(socket, S_DELETE); return 1; } // return, if we dont allow the download if (!download_real_allowed()) { // delete incoming socket and queue the matching download socket_destroy(socket, S_DELETE); socket_end(socket2, S_QUEUED); return 1; } download = socket2->data; trans = TRANS(download); // make sure to reset destination transfer first if (socket2->fd >= 0) close(socket2->fd); socket2->fd = socket->fd; socket->fd = -1; if (socket2->input >= 0 || socket2->output >= 0) { g_warning("download_fw_get_info(): download already has socket IOs"); } if (socket2->timer >= 0) gtk_timeout_remove(socket2->timer); socket2->timer = -1; // IP could have changed: if (socket2->ip_long != socket->ip_long) { /* g_warning("download_fw_get_info(): ip from incoming connection does not match socket ip %lu %lu", socket2->ip_long, socket->ip_long); */ socket2->ip_long = socket->ip_long; } socket2->port = socket->port; socket_destroy(socket, S_DELETE); socket = socket2; socket->cnt = 0; download_status_set(socket, S_INFO); lsize = strtol(size, NULL, 10); resume = download->resume; if (lsize <= 0 || (resume->comp_size && lsize != resume->comp_size)) { socket_end(socket, S_UNAVAILABLE); return 1; } segment = file_segment_find_free(resume, &stop); if (!stop) { socket_end(socket, S_QUEUED); return 1; } segment = file_segment_create_after(resume, segment, stop); if (!segment) { socket_end(socket, S_QUEUED); return 1; } file_segment_attach_to_download(socket, segment); if (download_open_file(download) == -1) { socket_end(socket, S_IO); return 1; } segment = download->csegment->data; // temp_str = g_strdup_printf("%ld 1", download->segment->start); temp_str = g_strdup_printf("%d", segment->start+segment->size); #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] sending [%s]\n", temp_str); #endif if (send_safe(socket->fd, temp_str, strlen(temp_str), strlen(temp_str)) == -1) { socket_end(socket, S_IO); g_free(temp_str); return 1; } g_free(temp_str); #ifdef ADVANCED_CONNECTION if (segment->stop - segment->start >= 50*1024 && trans->user_info->client == C_LOPSTER_ADV && !trans->is_dcc) { download->advanced = 1; if (!download_send_stop(socket)) return 1; } else { download->advanced = 0; } #endif download_status_set(socket, S_DOWNLOADING); socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(download_get_input), socket); return 1; } int download_timeout(gpointer data) { socket_t *socket = data; download_start(socket, FALSE); return 1; } void downloads_disable() { GList *dlist; socket_t *socket; transfer_t* trans; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (socket->type != S_DOWNLOAD) continue; if (!socket->data) continue; trans = TRANS(socket->data); if (trans->status != S_DOWNLOADING) continue; if (trans->user_info && trans->user_info->ignore_global[0]) continue; if (socket->input >= 0) { gdk_input_remove(socket->input); socket->input = -1; } } } void download_remove_dead() { GList *dlist; GList *dlist2; GList *result1 = NULL; socket_t *socket; download_t *download; int cnt; net_user_t* nu; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket || (socket->type != S_DOWNLOAD)) continue; download = socket->data; if (!download) continue; if (transfer_in_progress(TRANS(download))) continue; cnt = 0; dlist2 = download->nets; while (dlist2) { nu = dlist2->data; dlist2 = dlist2->next; if (!NET_CONNECTED(nu->net)) { download->nets = g_list_remove(download->nets, nu); g_free(nu->user); g_free(nu); cnt++; } } if (!download->nets) result1 = g_list_prepend(result1, socket); else if (cnt) TRANS(download)->needs_update = 1; } for (dlist = result1; dlist; dlist = dlist->next) { socket = dlist->data; socket_destroy(socket, S_CANCELED); } if (result1) g_list_free(result1); } gint download_get_info(gpointer data, gint source, GdkInputCondition condition) { socket_t *socket = data; download_t *download; transfer_t *trans; unsigned char buffer[1024]; int res; int cnt; long lsize; resume_t* resume; file_segment_t* segment; if (condition != GDK_INPUT_READ) { socket_end(socket, S_CONERROR); return 1; } gdk_input_remove(socket->input); socket->input = -1; // 128 bytes should do it, as we are trying to get the filessize. switch ((res = recv(source, buffer, 128, MSG_PEEK))) { case -1: socket_end(socket, S_CONERROR); return 1; case 0: socket_end(socket, S_CONERROR); return 1; default: break; } buffer[res] = 0; #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] info: read %d bytes\n", res); #endif download = socket->data; trans = TRANS(download); resume = download->resume; cnt = 0; lsize = 0; while (isdigit(buffer[cnt]) && cnt < 15) { lsize *= 10; lsize += buffer[cnt]-'0'; cnt++; // break here, ignored additional digits that are file content if (resume->comp_size && resume->comp_size == lsize) break; } if ((resume->comp_size && resume->comp_size != lsize) || lsize == 0) { g_warning("reported size (%ld) != resume size (%ld) -> setting unavailable [%s]\n", lsize, resume->comp_size, buffer); socket_end(socket, S_UNAVAILABLE); return 1; } // now pop the size packet from the socket. if (recv_safe(source, buffer, cnt, cnt) != cnt) { socket_end(socket, S_CONERROR); return 1; } #ifdef ADVANCED_CONNECTION segment = download->csegment->data; if (segment->stop - segment->start >= 50*1024 && trans->user_info->client == C_LOPSTER_ADV && !trans->is_dcc) { download->advanced = 1; if (!download_send_stop(socket)) return 1; } else { download->advanced = 0; } #endif download_status_set(socket, S_DOWNLOADING); socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(download_get_input), socket); return 1; } gint upload_get_info(gpointer data, gint source, GdkInputCondition condition) { socket_t *socket = data; upload_t *upload; #ifndef HAVE_LIBLCONV_H unsigned char buffer[1024]; #else char buffer[2047]; char lconv_buf[2047]; #endif int res; char* prog; if (condition != GDK_INPUT_READ) { socket_end(socket, S_CONERROR); return 1; } gdk_input_remove(socket->input); socket->input = -1; // 128 bytes should do it, as we are trying to get the filessize. switch ((res = recv(source, buffer, 128, 0))) { case -1: case 0: socket_end(socket, S_CONERROR); return 1; default: break; } buffer[res] = 0; #ifdef HAVE_LIBLCONV_H if (global.options.use_iconv) { lconv_conv(LCONV_SPEC, local_codeset, global.options.dest_codeset, lconv_buf, buffer); strcpy(buffer, lconv_buf); } #endif #ifdef TRANSFER_DEBUG printf("[UPLOAD] read [%s] %d\n", buffer, res); #endif prog = arg(buffer, 0); if (!prog) { socket_end(socket, S_CONERROR); return 1; } upload = socket->data; #ifdef TRANSFER_DEBUG printf("[UPLOAD] got progress %s\n", prog); #endif upload->segment = file_segment_new(strtol(prog, NULL, 10), upload->file->size); // check whether this is still a large upload if (upload->file->size >= global.limit.large_size *1024 *1024 && upload->segment->stop - upload->segment->start < global.limit.large_size *1024 *1024) global.limit.cur_large--; transfer_reset(TRANS(upload), upload->segment->start); if (!upload_open_file(upload)) { send_safe(socket->fd, "FILE NOT FOUND", 0, strlen("FILE NOT FOUND")); socket_end(socket, S_IO); return 1; } upload_status_set(socket, S_UPLOADING); socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(upload_push_output), socket); #ifdef ADVANCED_CONNECTION socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(upload_get_advanced), socket); #endif return 1; } gint download_send_info(gpointer data, gint source, GdkInputCondition condition) { char *temp_str = NULL; socket_t *socket = data; download_t* download; transfer_t* trans; long stop; int sent; file_segment_t* segment; if (condition != GDK_INPUT_WRITE) { socket_end(socket, S_CONERROR); return 1; } gdk_input_remove(socket->output); socket->output = -1; download = socket->data; trans = TRANS(download); segment = file_segment_find_free(download->resume, &stop); if (!stop) { socket_end(socket, S_QUEUED); return 1; } segment = file_segment_create_after(download->resume, segment, stop); if (!segment) { socket_end(socket, S_QUEUED); return 1; } file_segment_attach_to_download(socket, segment); if (download_open_file(download) == -1) { socket_end(socket, S_IO); return 1; } segment = download->csegment->data; #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] sending 'GET'\n"); #endif if (send_safe(source, "GET", 3, 3) != 3) { socket_end(socket, S_IO); return 1; } if (DL_GET_NET(download)) temp_str = g_strdup_printf("%s \"%s\" %d", DL_GET_NET(download)->user.username, download->file->winname, segment->start+segment->size); else temp_str = g_strdup_printf("%s \"%s\" %d", trans->user_info->nick, download->file->winname, segment->start+segment->size); download_status_set(socket, S_INFO); #ifdef TRANSFER_DEBUG printf("[DOWNLOAD] sending '%s'\n", temp_str); #endif #ifdef HAVE_LIBLCONV_H if (global.options.use_iconv) { char* lconv_buf = lconv_strdup_conv(LCONV_SPEC, global.options.dest_codeset, local_codeset, temp_str); if (send_safe(source, lconv_buf, strlen(lconv_buf), strlen(lconv_buf)) == -1) sent = 0; else sent = 1; free(lconv_buf); } else { #endif if (send_safe(source, temp_str, strlen(temp_str), strlen(temp_str)) == -1) sent = 0; else sent = 1; #ifdef HAVE_LIBLCONV_H } #endif g_free(temp_str); if (sent == 0) { socket_end(socket, S_IO); return 1; } socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(download_get_info), socket); return 1; } gint upload_send_info(gpointer data, gint source, GdkInputCondition condition) { char *temp_str = NULL; socket_t *socket = data; file_t* file; upload_t* upload; transfer_t* trans; struct stat st; #ifdef HAVE_LIBLCONV_H #endif int sent; file_node_t* node; if (condition != GDK_INPUT_WRITE){ socket_end(socket, S_CONERROR); return 1; } gdk_input_remove(socket->output); socket->output = -1; upload = socket->data; trans = TRANS(upload); node = file_tree_search_filename(FILE_TREE(global.lib), upload->file->longname); if (node || trans->is_dcc) file = upload->file; else file = NULL; if (!trans->is_dcc && (!node || ((node->flags & LIB_SHARED) == 0))) { #ifdef TRANSFER_DEBUG printf("[UPLOAD] *FILE NOT SHARED*\n"); #endif send_safe(socket->fd, "FILE NOT SHARED", 0, strlen("FILE NOT SHARED")); socket_end(socket, S_UNAVAILABLE); return 1; } else if (stat(file->longname, &st) < 0) { #ifdef TRANSFER_DEBUG printf("[UPLOAD] *FILE NOT FOUND*\n"); #endif send_safe(socket->fd, "FILE NOT FOUND", 0, strlen("FILE NOT FOUND")); socket_end(socket, S_IO); return 1; } #ifdef TRANSFER_DEBUG printf("[UPLOAD] sending 'SEND'\n"); #endif if (send_safe(source, "SEND", 4, 4) != 4) { socket_end(socket, S_IO); return 1; } //#ifdef ADVANCED_CONNECTION // temp_str = g_strdup_printf("%s \"%s\" 0%lu", // upload->nu.net->user.realname, // file->winname, file->size); //#else temp_str = g_strdup_printf("%s \"%s\" %lu", upload->nu.net->user.username, file->winname, file->size); //#endif upload_status_set(socket, S_INFO); #ifdef TRANSFER_DEBUG printf("[UPLOAD] sending [%s]\n", temp_str); #endif #ifdef HAVE_LIBLCONV_H if (global.options.use_iconv) { char* lconv_buf = lconv_strdup_conv(LCONV_SPEC, global.options.dest_codeset, local_codeset, temp_str); if (send_safe(source, lconv_buf, strlen(lconv_buf), strlen(lconv_buf)) == -1) sent = 0; else sent = 1; free(lconv_buf); } else { #endif if (send_safe(source, temp_str, strlen(temp_str), strlen(temp_str)) == -1) sent = 0; else sent = 1; #ifdef HAVE_LIBLCONV_H } #endif g_free(temp_str); if (sent == 0) { socket_end(socket, S_IO); return 1; } socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(upload_get_info), socket); return 1; } gint await_conn_ack(gpointer data, gint source, GdkInputCondition condition) { int res; char c; socket_t *socket = (socket_t *) data; if (condition != GDK_INPUT_READ) { socket_end(socket, S_CONERROR); return 1; } gdk_input_remove(socket->input); socket->input = -1; switch (res = recv(source, &c, 1, 0)) { case -1: #ifdef TRANSFER_DEBUG printf("[WAIT] rec1 error\n"); #endif socket_end(socket, S_CONERROR); return 1; case 0: #ifdef TRANSFER_DEBUG printf("[WAIT] received nothing\n"); #endif socket_end(socket, S_CONERROR); return 1; default: break; } #ifdef TRANSFER_DEBUG printf("[WAIT] got '%c'\n", c); #endif if (c != '1') { socket_end(socket, S_UNAVAILABLE); return 1; } if (socket->type == S_DOWNLOAD) socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(download_send_info), socket); else { socket->output = gdk_input_add(socket->fd, GDK_INPUT_WRITE, GTK_SIGNAL_FUNC(upload_send_info), socket); } return 1; } void transfer_connect_and_start(socket_t * socket) { if (socket->type == S_DOWNLOAD) download_status_set(socket, S_CONNECTING); else if (socket->type == S_UPLOAD) upload_status_set(socket, S_CONNECTING); if (!connect_socket(socket, "TCP", SOCK_STREAM)) { socket_end(socket, S_CONERROR); return; } socket->input = gdk_input_add(socket->fd, GDK_INPUT_READ, GTK_SIGNAL_FUNC(await_conn_ack), socket); } void upload_queue(upload_t* upload) { command_send(upload->nu.net, CMD_UPLOAD_LIMIT, upload->nu.user, upload->file->winname, estimate_upload_position(upload)); } static void upload_start_queued() { GtkCList* clist; GList *dlist; socket_t *socket; upload_t *upload; transfer_t *trans; int row; socket_t* winner = NULL; int winner_pri = -1; int winner_allowed = 0; int temp; GList* requested = NULL; int allowed; // start queued uploads clist = GTK_CLIST(lookup_widget(global.win, "transfer_up")); row = 0; while (1) { if (row >= clist->rows) { if (!winner) check_uploads = 0; break; } socket = gtk_clist_get_row_data(clist, row); if (socket->type != S_UPLOAD) { row++; continue; } upload = socket->data; trans = TRANS(upload); if (trans->status != S_QUEUED && trans->status != S_REQUESTED) { row++; continue; } // we are not connected to that net if (!NET_CONNECTED(upload->nu.net)) { socket_end(socket, S_DELETE); winner = NULL; break; } // offline user if (trans->status == S_QUEUED && trans->user_info->timestamp == 1) { socket_end(socket, S_DELETE); winner = NULL; break; } if (trans->status == S_REQUESTED) { requested = g_list_prepend(requested, socket); } // file not on disc if (upload->offline) { socket_end(socket, S_UNAVAILABLE); winner = NULL; break; } allowed = upload_allowed(upload); if (allowed == 1) { temp = user_info_priority(trans->user_info, NULL); } else if (allowed == 0) { temp = upload_eject(upload, 1); } else { row++; continue; } if (temp > winner_pri) { winner_pri = temp; winner = socket; winner_allowed = allowed; } row++; } // start the winner if (winner) { if (winner_allowed == 0) upload_eject((upload_t*)winner->data, 0); upload_start(winner); } // and queue outstanding requests for (dlist = requested; dlist; dlist = dlist->next) { socket = dlist->data; if (socket == winner) continue; upload = socket->data; upload_queue(upload); upload_status_set(socket, S_QUEUED); } g_list_free(requested); } static void download_start_queued() { GtkCTree* ctree; GList *dlist; socket_t *socket; resume_t *resume; transfer_t *trans; GtkCTreeNode* node; int temp; if (!download_real_allowed()) return; for (temp = 0; temp < 4; temp++) { // start queued or inactive transfer ctree = DownloadTree[temp]; node = GTK_CTREE_NODE (GTK_CLIST (ctree)->row_list); while (node) { resume = gtk_ctree_node_get_row_data(ctree, node); node = GTK_CTREE_ROW (node)->sibling; if (resume->active < 0) continue; if (resume->is_dcc) continue; if (resume->flags & RESUME_INACTIVE) continue; if ((resume->flags & RESUME_FREE_SEGMENT) == 0) continue; if ((resume->flags & RESUME_DONT_MSOURCE) && resume->active > 0) continue; dlist = resume->downloads; while (dlist) { socket = dlist->data; dlist = dlist->next; trans = TRANS(socket->data); if (trans->is_dcc) continue; if ((trans->status == S_PART || trans->status == S_QUEUED) && download_allowed(socket)) { resume->downloads = g_list_remove(resume->downloads, socket); resume->downloads = g_list_append(resume->downloads, socket); download_start(socket, FALSE); break; } } } } } static void transfer_start_queued() { if (check_uploads) upload_start_queued(); if (global.options.auto_resume && global.status.exiting == E_NONE && download_real_allowed()) download_start_queued(); } ////////////////////// // widgets ////////////////////// void on_toggle_dl_remove(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { int no = (int) user_data; global.options.dl_autoremove = global.options.dl_autoremove ^ no; } GtkWidget *create_dl_remove_popup(int val) { GtkWidget *mode_popup; GtkAccelGroup *mode_popup_accels; GtkWidget *mode; mode_popup = gtk_menu_new(); gtk_object_set_data(GTK_OBJECT(mode_popup), "mode_popup", mode_popup); mode_popup_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(mode_popup)); mode = gtk_check_menu_item_new_with_label("Finished"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & REMOVE_D_FINISHED) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_dl_remove, (gpointer)REMOVE_D_FINISHED); return mode_popup; } void on_toggle_autoretry(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { int no = (int) user_data; global.options.auto_retry = global.options.auto_retry ^ no; } void on_retry_configure(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data ATTR_UNUSED) { GtkWidget *win; GtkWidget *widget; win = create_retry_win(); widget = lookup_widget(win, "spinbutton43"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.retry_timeout[0])); widget = lookup_widget(win, "spinbutton44"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.retry_timeout[1])); widget = lookup_widget(win, "spinbutton45"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.retry_timeout[2])); widget = lookup_widget(win, "spinbutton46"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.retry_timeout[3])); widget = lookup_widget(win, "spinbutton47"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.retry_timeout[4])); gtk_widget_show(win); } void retry_timeout_check() { if (global.options.retry_timeout[1] < 60) global.options.retry_timeout[1] = 60; if (global.options.retry_timeout[3] < 60) global.options.retry_timeout[3] = 60; if (global.options.retry_timeout[4] < 60) global.options.retry_timeout[4] = 60; } GtkWidget *create_retry_popup(int val) { GtkWidget *mode_popup; GtkAccelGroup *mode_popup_accels; GtkWidget *mode; mode_popup = gtk_menu_new(); gtk_object_set_data(GTK_OBJECT(mode_popup), "mode_popup", mode_popup); mode_popup_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(mode_popup)); mode = gtk_check_menu_item_new_with_label("Timed out"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & RETRY_TIMEOUT) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_autoretry, (gpointer) RETRY_TIMEOUT); mode = gtk_check_menu_item_new_with_label("Rejected"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & RETRY_REJECT) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_autoretry, (gpointer) RETRY_REJECT); mode = gtk_check_menu_item_new_with_label("Incomplete"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & RETRY_INCOMPLETE) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_autoretry, (gpointer) RETRY_INCOMPLETE); mode = gtk_check_menu_item_new_with_label("Connection error"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & RETRY_CONERROR) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_autoretry, (gpointer) RETRY_CONERROR); mode = gtk_check_menu_item_new_with_label("Remotely queued"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & RETRY_REMOTE) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_autoretry, (gpointer) RETRY_REMOTE); mode = gtk_menu_item_new(); gtk_widget_ref(mode); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_widget_set_sensitive(mode, FALSE); mode = gtk_menu_item_new_with_label("Configure..."); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_retry_configure, NULL); return mode_popup; } void on_toggle_ul_remove(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { int no = (int) user_data; global.options.ul_autoremove = global.options.ul_autoremove ^ no; } GtkWidget *create_ul_remove_popup(int val) { GtkWidget *mode_popup; GtkAccelGroup *mode_popup_accels; GtkWidget *mode; mode_popup = gtk_menu_new(); gtk_object_set_data(GTK_OBJECT(mode_popup), "mode_popup", mode_popup); mode_popup_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(mode_popup)); mode = gtk_check_menu_item_new_with_label("Finished"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & REMOVE_U_FINISHED) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_ul_remove, (gpointer)REMOVE_U_FINISHED); mode = gtk_check_menu_item_new_with_label("Aborted"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (val & REMOVE_U_ABORTED) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_ul_remove, (gpointer)REMOVE_U_ABORTED); return mode_popup; } void on_dynamic_bandwidth_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data ATTR_UNUSED) { create_percent_win(); } void on_priority_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data ATTR_UNUSED) { GtkWidget* win; GtkWidget* widget; win = create_priority_win(); gtk_widget_show(win); widget = lookup_widget(win, "spinbutton63"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.upload_priority[PRI_FRIEND])); widget = lookup_widget(win, "spinbutton64"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.upload_priority[PRI_DOWNLOAD])); widget = lookup_widget(win, "spinbutton65"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.upload_priority[PRI_SHARE])); widget = lookup_widget(win, "spinbutton66"); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), (gfloat) (global.options.upload_priority[PRI_NONE])); } GtkWidget *create_advanced_popup() { GtkWidget *mode_popup; GtkAccelGroup *mode_popup_accels; GtkWidget *mode; mode_popup = gtk_menu_new(); gtk_object_set_data(GTK_OBJECT(mode_popup), "mode_popup", mode_popup); mode_popup_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(mode_popup)); mode = gtk_menu_item_new_with_label("Dynamic bandwidth settings..."); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_dynamic_bandwidth_activate, NULL); mode = gtk_menu_item_new_with_label("User priority settings..."); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_priority_activate, NULL); return mode_popup; } void on_toggle_autoresume(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data ATTR_UNUSED) { if (global.options.auto_resume) global.options.auto_resume = 0; else global.options.auto_resume = 1; setup_preferences(P_AUTORESUME); } void on_toggle_autosearch(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data ATTR_UNUSED) { if (global.options.auto_search) global.options.auto_search = 0; else global.options.auto_search = 1; setup_preferences(P_RSEARCH); } GtkWidget *create_advanced_popup2() { GtkWidget *mode_popup; GtkAccelGroup *mode_popup_accels; GtkWidget *mode; mode_popup = gtk_menu_new(); gtk_object_set_data(GTK_OBJECT(mode_popup), "mode_popup", mode_popup); mode_popup_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(mode_popup)); mode = gtk_check_menu_item_new_with_label("Autoresume"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (global.options.auto_resume) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_autoresume, NULL); mode = gtk_check_menu_item_new_with_label("Autosearch"); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); if (global.options.auto_search) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mode), TRUE); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_toggle_autosearch, NULL); mode = gtk_menu_item_new(); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_widget_set_sensitive(mode, FALSE); mode = gtk_menu_item_new_with_label("Autodelete Settings..."); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_button322_clicked, NULL); mode = gtk_menu_item_new_with_label("Import incomplete list..."); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_button311_clicked, NULL); mode = gtk_menu_item_new_with_label("Scan for dead files..."); gtk_widget_show(mode); gtk_container_add(GTK_CONTAINER(mode_popup), mode); gtk_signal_connect(GTK_OBJECT(mode), "activate", (GtkSignalFunc) on_button350_clicked, NULL); return mode_popup; } GtkWidget *create_upload_popup(upload_t* upload, share_t* share) { GtkWidget *popup; GtkWidget *user_popup; GtkWidget *item; GtkAccelGroup *popup_accels; GtkWidget *delete_upload; GtkWidget *separator; GtkWidget *trennlinie16; GtkWidget *customize_list2; GtkCList *clist; int item_num; char item_str[1024]; transfer_t* trans; popup = gtk_menu_new(); gtk_object_set_data(GTK_OBJECT(popup), "popup", popup); popup_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(popup)); clist = GTK_CLIST(lookup_widget(global.win, "transfer_up")); item_num = g_list_length(clist->selection); if (upload) trans = TRANS(upload); else trans = TRANS(share); if (upload || share) { if (item_num > 1) sprintf(item_str, "Delete Selected (%d)", item_num); else sprintf(item_str, "Delete Upload"); delete_upload = gtk_menu_item_new_with_label(item_str); gtk_widget_show(delete_upload); gtk_container_add(GTK_CONTAINER(popup), delete_upload); gtk_signal_connect(GTK_OBJECT(delete_upload), "activate", GTK_SIGNAL_FUNC(on_delete_upload_activate), NULL); separator = gtk_menu_item_new(); gtk_widget_show(separator); gtk_container_add(GTK_CONTAINER(popup), separator); gtk_widget_set_sensitive(separator, FALSE); if (upload) { if (!transfer_in_progress(trans) && trans->status != S_FINISHED) { if (item_num > 1) sprintf(item_str, "Allow Selected (%d)", item_num); else sprintf(item_str, "Allow Upload"); delete_upload = gtk_menu_item_new_with_label(item_str); gtk_widget_show(delete_upload); gtk_container_add(GTK_CONTAINER(popup), delete_upload); gtk_signal_connect(GTK_OBJECT(delete_upload), "activate", GTK_SIGNAL_FUNC(on_allow_upload_activate), NULL); } if (item_num > 1) sprintf(item_str, "Add to Subscription list (%d)", item_num); else sprintf(item_str, "Add to Subscription list"); delete_upload = gtk_menu_item_new_with_label(item_str); gtk_widget_show(delete_upload); gtk_container_add(GTK_CONTAINER(popup), delete_upload); gtk_signal_connect(GTK_OBJECT(delete_upload), "activate", GTK_SIGNAL_FUNC(on_add_subscription_activate), NULL); separator = gtk_menu_item_new(); gtk_widget_show(separator); gtk_container_add(GTK_CONTAINER(popup), separator); gtk_widget_set_sensitive(separator, FALSE); item = create_open_menu(upload->file->media_type, upload->file->longname, 1); gtk_container_add(GTK_CONTAINER(popup), item); separator = gtk_menu_item_new(); gtk_widget_show(separator); gtk_container_add(GTK_CONTAINER(popup), separator); gtk_widget_set_sensitive(separator, FALSE); } item = gtk_menu_item_new_with_label("User Menu"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); if (upload) user_popup = create_user_popup(M_UPLOAD, upload); else user_popup = create_user_popup(M_SHARE, share); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), user_popup); trennlinie16 = gtk_menu_item_new(); gtk_widget_show(trennlinie16); gtk_container_add(GTK_CONTAINER(popup), trennlinie16); gtk_widget_set_sensitive(trennlinie16, FALSE); } customize_list2 = gtk_menu_item_new_with_label("Customize List"); gtk_widget_show(customize_list2); gtk_container_add(GTK_CONTAINER(popup), customize_list2); gtk_signal_connect(GTK_OBJECT(customize_list2), "activate", GTK_SIGNAL_FUNC(on_customize_list_activate), NULL); return popup; } void on_switch_clone(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { net_user_t* nu = user_data; if (!g_list_find(popup_download->nets, nu)) return; popup_download->nets = g_list_remove(popup_download->nets, nu); popup_download->nets = g_list_prepend(popup_download->nets, nu); // download_queued_update(popup_download); } GtkWidget *create_switch_popup(download_t *download) { GtkWidget *popup; GtkWidget *item; char item_str[1024]; net_user_t* nu; GList* dlist; if (!download) return NULL; if (g_list_length(download->nets) < 2) return NULL; popup = gtk_menu_new(); for (dlist = download->nets; dlist; dlist = dlist->next) { nu = dlist->data; sprintf(item_str, "%s@%s%s", nu->user?nu->user:"_unknown_", nu->net?nu->net->name:"_unknown_", NET_CONNECTED(nu->net)?"":" (Offline)"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); if (dlist == download->nets) { gtk_widget_set_sensitive(item, FALSE); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); } else { gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_switch_clone), nu); } } return popup; } GtkWidget *create_transfer_popup(download_t *download, int num) { GtkWidget *user_popup; GtkWidget *popup; GtkWidget *item; char item_str[1024]; transfer_t* trans = TRANS(download); popup = gtk_menu_new(); if (!download) return popup; popup_download = download; if (num > 1) sprintf(item_str, "Cancel Selected (%d)", num); else sprintf(item_str, "Cancel Download"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_cancel_download_activate), NULL); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); if (transfer_in_progress(trans)) { if (num > 1) sprintf(item_str, "Restart Selected (%d)", num); else sprintf(item_str, "Restart Download"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_retry_download_activate), NULL); } else if (trans->status == S_QUEUED) { item = gtk_menu_item_new_with_label("Force Download"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_force_download_activate), NULL); } else if (trans->status != S_FINISHED) { if (trans->is_dcc) sprintf(item_str, "Start DCC"); else if (num > 1) sprintf(item_str, "Retry Selected (%d)", num); else sprintf(item_str, "Retry Download"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_retry_download_activate), NULL); } else { sprintf(item_str, "Retry Download"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); } item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); item = gtk_menu_item_new_with_label("User Menu"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); user_popup = create_user_popup(M_DOWNLOAD, download); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), user_popup); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); user_popup = create_switch_popup(download); if (user_popup) { item = gtk_menu_item_new_with_label("Switch To Clone"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), user_popup); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); } return popup; } static void on_multisource_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GtkCTree *ctree; GtkCTreeNode *node; resume_t *resume; GList* dlist; int multi = (user_data == NULL); ctree = GTK_CTREE(global.popup_list); if (!ctree) return; for (dlist = GTK_CLIST(ctree)->selection; dlist; dlist = dlist->next) { node = GTK_CTREE_NODE(dlist->data); if (GTK_CTREE_ROW(node)->parent == NULL) { resume = gtk_ctree_node_get_row_data(ctree, node); if (multi) resume->flags &= ~RESUME_DONT_MSOURCE; else resume->flags |= RESUME_DONT_MSOURCE; } } resume_save(NULL); } GtkWidget *create_resume_popup(resume_t * resume, int num) { GtkWidget *popup; GtkWidget *item; char item_str[1024]; popup = gtk_menu_new(); if (!resume) return popup; if (num > 1) sprintf(item_str, "Cancel Selected (%d)", num); else sprintf(item_str, "Cancel File"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_resume_cancel_activate), NULL); if (resume->flags & RESUME_FINISHED) gtk_widget_set_sensitive(item, FALSE); if (num > 1) sprintf(item_str, "Delete Selected (%d)", num); else sprintf(item_str, "Delete File"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_resume_delete_activate), NULL); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); if (num > 1) { sprintf(item_str, "Deactivated (%d)", num); } else { strcpy(item_str, "Deactivated"); } item = gtk_check_menu_item_new_with_label(item_str); if (resume->flags & RESUME_DEACTIVATED) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); if (resume->flags & RESUME_DEACTIVATED) { gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_resume_thaw_activate), NULL); } else { gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_resume_freeze_activate), NULL); } if (num > 1) { sprintf(item_str, "Single Source Mode (%d)", num); } else { strcpy(item_str, "Single Source Mode"); } item = gtk_check_menu_item_new_with_label(item_str); if (resume->flags & RESUME_DONT_MSOURCE) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); if (resume->flags & RESUME_DONT_MSOURCE) { gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_multisource_activate), NULL); } else { gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_multisource_activate), GINT_TO_POINTER(1)); } item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); item = create_open_menu(mtype_get(resume->filename), resume->filename, 1); gtk_container_add(GTK_CONTAINER(popup), item); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); if (num > 1) sprintf(item_str, "Search Selected (%d)", num); else sprintf(item_str, "Search File"); item = gtk_menu_item_new_with_label(item_str); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_resume_search_activate), NULL); item = gtk_menu_item_new_with_label("Search all"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_button245_clicked), NULL); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); item = gtk_menu_item_new_with_label("Configure File..."); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_resume_configure), resume); if (resume->flags & RESUME_FINISHED) gtk_widget_set_sensitive(item, FALSE); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); return popup; } GtkWidget *create_download_popup() { GtkWidget *popup = NULL; GtkWidget *item; int item_num; socket_t *socket = NULL; download_t *download = NULL; resume_t *resume = NULL; GtkCTree *ctree; GtkCTreeNode *node; ctree = GTK_CTREE(global.popup_list); node = gtk_ctree_node_nth(ctree, global.popup_row); item_num = g_list_length(GTK_CLIST(ctree)->selection); if (node) { if (GTK_CTREE_ROW(node)->parent != NULL) { socket = gtk_ctree_node_get_row_data(ctree, node); download = socket->data; } else resume = gtk_ctree_node_get_row_data(ctree, node); } if (download) popup = create_transfer_popup(download, item_num); else popup = create_resume_popup(resume, item_num); if (download || resume) { item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); } item = gtk_menu_item_new_with_label("Customize List"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_customize_list_activate), NULL); return popup; } void on_cancel2_clicked(GtkButton * button ATTR_UNUSED, gpointer user_data ATTR_UNUSED) { char *nick; nick = (char *) gtk_object_get_data(GTK_OBJECT(global.file_win), "nick"); gtk_object_set_data(GTK_OBJECT(global.file_win), "nick", NULL); if (nick) g_free(nick); gtk_widget_hide(global.file_win); } void on_ok2_clicked(GtkButton * button, gpointer user_data) { char *filename; char *nick; net_t* net; filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(global.file_win)); nick = gtk_object_get_data(GTK_OBJECT(global.file_win), "nick"); net = gtk_object_get_data(GTK_OBJECT(global.file_win), "network"); if (filename && *filename && nick && net) dcc_send_file(nick, filename, net); on_cancel2_clicked(button, user_data); } void dcc_send_file(char *nick, char *file, net_t* net) { char *command; struct stat st; upload_t *new_trans; struct sockaddr_in localaddr; int len = sizeof(struct sockaddr_in); socket_t *socket; unsigned long ip_long; socket_t* s_socket; if (!nick || !file || !net) { printf("no nick/file/net\n"); return; } if (stat(file, &st) < 0) { info_dialog("File does not exist!"); return; } if (!NET_CONNECTED(net)) { info_dialog("Not connected!"); return; } if (!global.upload_socket) { info_dialog("You cannot send files, if you are firewalled (port 0)"); return; } new_trans = upload_new(net, file, nick, 0); TRANS(new_trans)->is_dcc = TRUE; // hide path g_free(new_trans->file->winname); new_trans->file->winname = g_strdup(new_trans->file->filename); socket = socket_new(S_UPLOAD); socket->data = new_trans; upload_show(socket); upload_start(socket); s_socket = network_socket(net); getsockname(s_socket->fd, (struct sockaddr *)&localaddr, &len); if (global.my_ip != INADDR_NONE && global.my_ip != localaddr.sin_addr.s_addr) { client_message("DCC", "Lopster detected local ip [%s]", ntoa(localaddr.sin_addr.s_addr)); client_message("DCC", "But /whois reported ip [%s], using this one for DCC file transfer", ntoa(global.my_ip)); ip_long = global.my_ip; } else { ip_long = localaddr.sin_addr.s_addr; } command = g_strdup_printf("\001SEND %s %lu %d \"%s\" %lu %s %d\001", net->user.username, BSWAP32(ip_long), global.upload_socket?ntohs(global.upload_socket->port):0, new_trans->file->winname, (unsigned long) st.st_size, "checksum", 0); command_send(net, CMD_NOTICE, nick, command); g_free(command); { chat_page_t* page = chat_page_get_printable(); chat_print_time_stamp(page, M_PUBLIC); chat_print_prefix(page, 1); chat_print_text(page, M_PUBLIC, "message", "Sending"); chat_print_text(page, M_PUBLIC, "user", " ("); chat_print_file(page, new_trans->file->longname, new_trans->file->filename); chat_print_text(page, M_PUBLIC, "user", ") "); chat_print_text(page, M_PUBLIC, "message", "to"); chat_print_text(page, M_PUBLIC, "user", " <"); chat_print_nick(page, M_PUBLIC, nick, net); chat_print_text(page, M_PUBLIC, "user", ">\n"); } } void dcc_select_file(char *nick, net_t* net) { GtkWidget *temp; char *str; if (!nick) return; if (!global.file_win) { str = g_strdup_printf("Select file to send [%s]", nick); global.file_win = gtk_file_selection_new(str); g_free(str); gtk_widget_show(global.file_win); temp = GTK_FILE_SELECTION(global.file_win)->ok_button; if (temp) gtk_signal_connect(GTK_OBJECT(temp), "clicked", GTK_SIGNAL_FUNC(on_ok2_clicked), NULL); temp = GTK_FILE_SELECTION(global.file_win)->cancel_button; if (temp) gtk_signal_connect(GTK_OBJECT(temp), "clicked", GTK_SIGNAL_FUNC(on_cancel2_clicked), NULL); } else { gtk_widget_show(global.file_win); } str = gtk_object_get_data(GTK_OBJECT(global.file_win), "nick"); if (str) g_free(str); gtk_object_set_data(GTK_OBJECT(global.file_win), "nick", g_strdup(nick)); gtk_object_set_data(GTK_OBJECT(global.file_win), "network", net); } socket_t* dcc_create(net_t* net, char* nick, char* filename, unsigned long ip, short port, unsigned long size, int speed) { chat_page_t* page; download_t *download; socket_t *socket; file_t* file; if (size == 0) { page = chat_page_get_printable(); chat_print_time_stamp(page, M_PUBLIC); chat_print_prefix(page, 1); chat_print_text(page, M_PUBLIC, "user", "<"); chat_print_nick(page, M_PUBLIC, nick, net); chat_print_text(page, M_PUBLIC, "user", "> "); chat_print_text(page, M_PUBLIC, "message", "is sending a 0 byte file, ignoring "); chat_print_text(page, M_PUBLIC, "user", filename); chat_print_text(page, M_PUBLIC, "user", "\n"); return NULL;; } page = chat_page_get_printable(); chat_print_time_stamp(page, M_PUBLIC); chat_print_prefix(page, 1); chat_print_text(page, M_PUBLIC, "user", "<"); chat_print_nick(page, M_PUBLIC, nick, net); chat_print_text(page, M_PUBLIC, "user", "> "); chat_print_text(page, M_PUBLIC, "message", "is sending "); chat_print_text(page, M_PUBLIC, "user", filename); chat_print_text(page, M_PUBLIC, "user", "\n"); if (ntohs(port) == 0 && !global.upload_socket) { client_message("Message", "Both systems are firewalled. Unable to comply"); return NULL; } file = file_new(); file_set_winname(file, filename); file->net = net; file->user = g_strdup(nick); file->md5 = g_strdup(""); file->size = size; file->linespeed = speed; file->ip = ip; socket = download_create(file, NULL, NULL, NULL, 1); socket->port = port; download = socket->data; return socket; } int dcc_check_message(char *from ATTR_UNUSED, char *message, net_t* net) { char *nick; unsigned long ip_long; int port; char *filename; unsigned long filesize; char *command; char *checksum; int speed; socket_t* socket; if (!message || strlen(message) < 2) return 0; if (*message == '\001' && message[strlen(message) - 1] == '\001') { message++; message[strlen(message) - 1] = 0; command = arg(message, 0); if (command && strncmp(command, "SEND", 4)) return 0; nick = arg(NULL, 0); ip_long = strtoul(arg(NULL, 0), NULL, 10); port = atoi(arg(NULL, 0)); filename = arg(NULL, 0); filesize = strtoul(arg(NULL, 0), NULL, 10); checksum = arg(NULL, 0); speed = atoi(arg(NULL, 0)); port = ntohs(port); // network->host ip_long = BSWAP32(ip_long); // little ->host socket = dcc_create(net, nick, filename, ip_long, port, filesize, speed); if (socket && global.options.allow_dcc) download_start(socket, 1); return 1; } return 0; } void resolve_check(); int global_timer(gpointer data ATTR_UNUSED) { char comm[2048]; GtkWidget *temp; GList *dlist; socket_t *socket; share_t *share; upload_t *upload; download_t *download; static int cnt = 0; user_timestamp_t *stamp; struct timeval tv; speed_t *speed; transfer_t* trans; int i1; GList* alist1 = NULL; GList* alist2 = NULL; cnt++; global.current_time = time(NULL); if (global.status.exiting == E_SAFE && global.limit.cur_downloads == 0 && global.limit.cur_uploads == 0) { global_exit(); return 1; } if (global.socket_win) { for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = (socket_t *) (dlist->data); socket_update_clist(socket); } } if (global.options.time_display) print_topright_corner(); gettimeofday(&tv, 0); dlist = global.userstamp; while (dlist) { stamp = dlist->data; dlist = dlist->next; if (tv.tv_sec - stamp->tv.tv_sec > 100) { client_message("Message", "Ping to <%s> timed out after 100 seconds!", stamp->user); global.userstamp = g_list_remove(global.userstamp, stamp); g_free(stamp->user); g_free(stamp); } } dlist = global.appearance; while (dlist) { stamp = dlist->data; dlist = dlist->next; if (tv.tv_sec - stamp->tv.tv_sec > 3600) { global.appearance = g_list_remove(global.appearance, stamp); g_free(stamp->user); g_free(stamp); } } dlist = global.speed_requests; while (dlist) { speed = dlist->data; dlist = dlist->next; if (global.current_time - speed->sent > SPEED_LIFE) speed_remove(speed); } ping_inc_counter(1); dlist = global.sockets; while (dlist) { socket = dlist->data; dlist = dlist->next; if (!socket) { g_warning("NO SOCKET"); continue; } switch (socket->type) { case S_BROWSE: socket->cnt++; if (socket->cnt >= socket->max_cnt) { socket_destroy(socket, 0); } break; case S_HTTP: socket->cnt++; if (socket->cnt >= socket->max_cnt) { socket_destroy(socket, 0); } break; case S_SERVER: if (socket->fd >= 0) { net_t* net = socket->data; socket->cnt++; if (socket->cnt >= socket->max_cnt) { socket->cnt = 0; net->active_server->ip = INADDR_NONE; server_disconnect(net->active_server, "Server connection timed out", 1); } } break; case S_DATA: break; case S_DOWNLOAD: download = socket->data; trans = TRANS(download); if (!download) break; if (transfer_in_progress(trans)) { socket->cnt++; i1 = global.current_time - trans->start_time; if (!i1) i1 = 1; if (download->fd >= 0 && download->csegment && global.current_time - trans->start_time > 30 && download->resume->active >= global.limit.download_abort_number && trans->transferred / i1 < (signed)global.limit.download_abort_limit) { socket_end(socket, S_CANCELED); } else if (socket->cnt >= socket->max_cnt) { socket_end(socket, S_TIMEOUT); } else { if (download->csegment) { file_segment_t* segment = download->csegment->data; int last_prog, first_prog; trans->hist_pos++; if (trans->hist_pos >= TRANSFER_HISTORY_TIME) trans->hist_pos = 0; trans->history[trans->hist_pos] = segment->start + segment->size; if (trans->hist_cnt < TRANSFER_HISTORY_TIME) trans->hist_cnt++; last_prog = trans->hist_pos; first_prog = (last_prog + TRANSFER_HISTORY_TIME - trans->hist_cnt + 1) % TRANSFER_HISTORY_TIME; trans->rate = (double) (trans->history[last_prog] - trans->history[first_prog]) / trans->hist_cnt; trans->timeleft = -(int) ((segment->stop - segment->start - segment->size) / trans->rate); } if ((cnt % global.network.transfer_delay) == 0) { trans->needs_update = 1; if (download->resume->active > 0) { download->resume->needs_update = 1; } } } } break; case S_SHARE: share = socket->data; if (!share) break; trans = TRANS(share); // update the userinfo if (NET_CONNECTED(share->nu.net) && trans->user_info->timestamp > 1) user_info_get(trans->user_info, share->nu.net); if ((StatusInfo[trans->status] == T_CURRENT) || (StatusInfo[trans->status] == T_TRANSFER)) { socket->cnt++; if (socket->cnt >= socket->max_cnt) { socket_end(socket, S_TIMEOUT); } else { if (share->buffer) { int last_prog, first_prog; trans->hist_pos++; if (trans->hist_pos >= TRANSFER_HISTORY_TIME) trans->hist_pos = 0; trans->history[trans->hist_pos] = share->buffer->consumed; if (trans->hist_cnt < TRANSFER_HISTORY_TIME) trans->hist_cnt++; last_prog = trans->hist_pos; first_prog = (last_prog + TRANSFER_HISTORY_TIME - trans->hist_cnt + 1) % TRANSFER_HISTORY_TIME; trans->rate = (double) (trans->history[last_prog] - trans->history[first_prog]) / trans->hist_cnt; trans->timeleft = (int) ((share->buffer->datasize - share->buffer->consumed) / trans->rate); } if ((cnt % global.network.transfer_delay) == 0) { share_update(socket); } } } break; case S_UPLOAD: upload = socket->data; if (!upload) break; trans = TRANS(upload); // update the userinfo if (NET_CONNECTED(upload->nu.net) && trans->user_info->timestamp > 1) user_info_get(trans->user_info, upload->nu.net); if (transfer_in_progress(trans)) { socket->cnt++; if (socket->cnt >= socket->max_cnt) { socket_end(socket, S_TIMEOUT); } else { if (upload->segment) { int last_prog, first_prog; trans = trans; trans->hist_pos++; if (trans->hist_pos >= TRANSFER_HISTORY_TIME) trans->hist_pos = 0; trans->history[trans->hist_pos] = upload->segment->start+upload->segment->size; if (trans->hist_cnt < TRANSFER_HISTORY_TIME) trans->hist_cnt++; last_prog = trans->hist_pos; first_prog = (last_prog + TRANSFER_HISTORY_TIME - trans->hist_cnt + 1) % TRANSFER_HISTORY_TIME; trans->rate = (double) (trans->history[last_prog] - trans->history[first_prog]) / trans->hist_cnt; trans->timeleft = (int) ((upload->segment->stop - upload->segment->start - upload->segment->size) / trans->rate); if (upload->access && upload->node) { upload->access->temp = upload->segment->size; alist1 = g_list_prepend(alist1, upload->node); } } if ((cnt % global.network.transfer_delay) == 0) { upload_update(socket); } } } break; case S_UNKNOWN: socket->cnt++; if (socket->cnt >= socket->max_cnt) socket_destroy(socket, 0); break; default: g_warning("unknown socket type in global_timer()"); break; } } downloads_update(); { access_t* access; access_t* access2; GtkCTreeNode* node; GtkCTreeNode* parent; for (dlist = alist1; dlist; dlist = dlist->next) { node = dlist->data; access = access_get_access(node); parent = GTK_CTREE_ROW(node)->parent; if (!parent) continue; access2 = access_get_access(parent); if (!access2) continue; if (!g_list_find(alist2, parent)) { alist2 = g_list_prepend(alist2, parent); access2->temp = access->temp; } else { access2->temp += access->temp; } access_ctree_update(node, access); } g_list_free(alist1); parent = NULL; for (dlist = alist2; dlist; dlist = dlist->next) { node = dlist->data; parent = GTK_CTREE_ROW(node)->parent; access = access_get_access(node); if (!access) continue; global.statistic.file_access->temp += access->temp; access_ctree_update(node, access); } g_list_free(alist2); if (global.statistic.file_access->temp > 0) access_ctree_update(parent, global.statistic.file_access); } statistic_update(&global.statistic); if (notebook_page_visible(7)) statistic_output(&global.statistic); // updating stats temp = lookup_widget(global.win, "label534"); sprintf(comm, "%d/%d", global.limit.cur_downloads, global.limit.cur_real_downloads); gtk_label_set_text(GTK_LABEL(temp), comm); temp = lookup_widget(global.win, "label547"); sprintf(comm, "%d/%d/%d", global.limit.cur_uploads, global.limit.cur_real_uploads, global.limit.cur_large); gtk_label_set_text(GTK_LABEL(temp), comm); temp = lookup_widget(global.win, "label1689"); sprintf(comm, "%d/%d", global.limit.cur_real_downloads, global.limit.cur_real_uploads); gtk_label_set_text(GTK_LABEL(temp), comm); global.down_width.value = statistic_last_value(&global.statistic, 0); global.up_width.value = statistic_last_value(&global.statistic, 1); draw_band_width(&global.down_width, 0); draw_band_width(&global.up_width, 0); if (cnt % global.network.transfer_delay == 0) cnt = 0; sockets_enable(); update_queue_length(); resume_remove_outdated(); // also starts resume searches transfer_start_queued(); search_next(NULL); network_connect_next(); activate_auto_afk(); resolve_check(); return 1; } void on_button_band_cancel_clicked(GtkButton * button ATTR_UNUSED, gpointer user_data) { GtkWidget *win; win = GTK_WIDGET(user_data); gtk_widget_destroy(win); } void on_button_band_ok_clicked(GtkButton * button, gpointer user_data) { user_info_t* userinfo; GtkWidget *temp; GtkObject *adj; int upload; userinfo = user_data; if (!userinfo) return; adj = gtk_object_get_data(GTK_OBJECT(button), "adj"); upload = !((int)gtk_object_get_data(GTK_OBJECT(button), "type")); if (!adj) return; userinfo->limit[upload] = (int)(GTK_ADJUSTMENT(adj)->value); temp = lookup_widget(GTK_WIDGET(button), "checkbutton"); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(temp))) userinfo->ignore_global[upload] = 1; else userinfo->ignore_global[upload] = 0; temp = lookup_widget(GTK_WIDGET(button), "win"); on_button_band_cancel_clicked(button, temp); } static void on_adj2_value_changed(GtkAdjustment *adjustment) { char str[1024]; GtkWidget* entry; GtkWidget* label; entry = gtk_object_get_data(GTK_OBJECT(adjustment), "entry"); label = gtk_object_get_data(GTK_OBJECT(adjustment), "label"); gtk_label_set_text(GTK_LABEL(label), print_speed(str, adjustment->value, 1)); gtk_entry_set_text(GTK_ENTRY(entry), print_bytes(str, adjustment->value)); } static void on_band_entry_activate(GtkEntry* entry, GtkAdjustment* adj) { char *text = gtk_entry_get_text(entry); gtk_adjustment_set_value(adj, (gfloat)extract_bytes(text)); } void create_bandwidth_win(user_info_t* userinfo, int download) { GtkWidget *win; GtkWidget *frame; GtkWidget *vbox175; GtkWidget *vbox176; GtkWidget *hbox; GtkWidget *hbox2; GtkWidget *entry; GtkWidget *label; GtkWidget *label797; GtkWidget *hseparator34; GtkWidget *frame296; GtkWidget *hbox634; GtkWidget *button275; GtkWidget *button276; GtkWidget *hscale1; GtkWidget *checkbutton; GtkObject *adj; char str[1024]; if (!userinfo) return; win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_object_set_data(GTK_OBJECT(win), "win", win); gtk_widget_set_usize(win, 500, -2); gtk_window_set_title(GTK_WINDOW(win), "User Bandwidth"); gtk_window_set_default_size(GTK_WINDOW(win), 170, -1); gtk_window_set_policy(GTK_WINDOW(win), FALSE, FALSE, FALSE); frame = gtk_frame_new(NULL); gtk_widget_show(frame); gtk_container_add(GTK_CONTAINER(win), frame); gtk_container_set_border_width(GTK_CONTAINER(frame), 5); vbox175 = gtk_vbox_new(FALSE, 5); gtk_widget_show(vbox175); gtk_container_add(GTK_CONTAINER(frame), vbox175); gtk_container_set_border_width(GTK_CONTAINER(vbox175), 5); vbox176 = gtk_vbox_new(FALSE, 5); gtk_widget_show(vbox176); gtk_box_pack_start(GTK_BOX(vbox175), vbox176, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(vbox176), hbox, FALSE, FALSE, 0); if (download) label = gtk_label_new("Specify download bandwidth for"); else label = gtk_label_new("Specify upload bandwidth for"); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label797 = gtk_label_new(userinfo->nick); gtk_widget_show(label797); gtk_box_pack_start(GTK_BOX(hbox), label797, FALSE, FALSE, 0); gtk_widget_set_style(label797, global.styles[STYLE_PREF]); hbox = gtk_hbox_new(FALSE, 5); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(vbox176), hbox, FALSE, FALSE, 0); if (download) adj = gtk_adjustment_new (userinfo->limit[0], 0, global.down_width.limit, 0, 0, 0); else adj = gtk_adjustment_new (userinfo->limit[1], 0, global.up_width.limit, 0, 0, 0); hscale1 = gtk_hscale_new (GTK_ADJUSTMENT (adj)); gtk_widget_show (hscale1); gtk_box_pack_start (GTK_BOX (hbox), hscale1, TRUE, TRUE, 0); gtk_scale_set_draw_value (GTK_SCALE (hscale1), FALSE); gtk_signal_connect(GTK_OBJECT(adj), "value-changed", on_adj2_value_changed, NULL); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), print_bytes(str, userinfo->limit[(!download)])); gtk_widget_show(entry); gtk_widget_set_usize (entry, 100, -2); gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); gtk_signal_connect (GTK_OBJECT (entry), "activate", GTK_SIGNAL_FUNC (on_band_entry_activate), adj); hbox2 = gtk_hbox_new (FALSE, 1); gtk_widget_set_usize (hbox2, 75, -2); gtk_widget_show (hbox2); gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0); label = gtk_label_new(print_speed(str, userinfo->limit[(!download)], 1)); gtk_widget_show(label); gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0); gtk_object_set_data(GTK_OBJECT(adj), "entry", entry); gtk_object_set_data(GTK_OBJECT(adj), "label", label); checkbutton = gtk_check_button_new_with_label ("Ignore global bandwidth limit for this user"); gtk_object_set_data (GTK_OBJECT (win), "checkbutton", checkbutton); gtk_widget_show (checkbutton); gtk_box_pack_start(GTK_BOX(vbox176), checkbutton, FALSE, FALSE, 0); if (userinfo->ignore_global[(!download)]) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), TRUE); hseparator34 = gtk_hseparator_new(); gtk_widget_show(hseparator34); gtk_box_pack_start(GTK_BOX(vbox175), hseparator34, FALSE, FALSE, 0); frame296 = gtk_frame_new(NULL); gtk_widget_show(frame296); gtk_box_pack_start(GTK_BOX(vbox175), frame296, FALSE, FALSE, 0); gtk_widget_set_usize(frame296, -2, 41); gtk_frame_set_shadow_type(GTK_FRAME(frame296), GTK_SHADOW_IN); hbox634 = gtk_hbox_new(TRUE, 5); gtk_widget_show(hbox634); gtk_container_add(GTK_CONTAINER(frame296), hbox634); gtk_container_set_border_width(GTK_CONTAINER(hbox634), 5); button275 = gtk_button_new_with_label("Ok"); gtk_object_set_data(GTK_OBJECT(button275), "adj", adj); gtk_object_set_data(GTK_OBJECT(button275), "type", (gpointer)(download)); gtk_widget_show(button275); gtk_box_pack_start(GTK_BOX(hbox634), button275, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button275), "clicked", on_button_band_ok_clicked, (gpointer)userinfo); button276 = gtk_button_new_with_label("Cancel"); gtk_widget_show(button276); gtk_box_pack_start(GTK_BOX(hbox634), button276, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button276), "clicked", on_button_band_cancel_clicked, win); gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL); gtk_widget_show(win); return; } GtkWidget* create_bandwidth_popup(user_info_t* userinfo) { GtkWidget* item = NULL; GtkWidget* item2; GtkWidget* popup; if (!userinfo) return NULL; item = gtk_menu_item_new_with_label("Set Bandwidth"); gtk_widget_show(item); popup = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), popup); item2 = gtk_menu_item_new_with_label("Download..."); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_enter_bandwidth1_activate), userinfo); item2 = gtk_menu_item_new_with_label("Upload..."); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_enter_bandwidth2_activate), userinfo); return item; } static void on_button_band_cancel2_clicked(GtkButton* button, GtkObject* user_data) { GtkWidget* win; GList* list; (void)button; list = gtk_object_get_data(user_data, "info_list"); g_list_free(list); list = gtk_object_get_data(user_data, "adj_list1"); g_list_free(list); list = gtk_object_get_data(user_data, "adj_list2"); g_list_free(list); list = gtk_object_get_data(user_data, "e_list1"); g_list_free(list); list = gtk_object_get_data(user_data, "e_list2"); g_list_free(list); list = gtk_object_get_data(user_data, "c_list1"); g_list_free(list); list = gtk_object_get_data(user_data, "c_list2"); g_list_free(list); win = GTK_WIDGET(user_data); gtk_widget_destroy(win); } static void on_button_band_ok2_clicked(GtkButton* button, GtkObject* user_data) { GList* dlist = gtk_object_get_data(user_data, "info_list"); GList* dlistl1 = gtk_object_get_data(user_data, "adj_list1"); GList* dlistl2 = gtk_object_get_data(user_data, "adj_list2"); GList* dlistd = gtk_object_get_data(user_data, "e_list1"); GList* dlistu = gtk_object_get_data(user_data, "e_list2"); GList* dlistc1 = gtk_object_get_data(user_data, "c_list1"); GList* dlistc2 = gtk_object_get_data(user_data, "c_list2"); for (; dlist && dlistd && dlistu && dlistl1 && dlistl2 && dlistc1 && dlistc2; dlist = dlist->next, dlistd = dlistd->next, dlistu = dlistu->next, dlistl1 = dlistl1->next, dlistl2 = dlistl2->next, dlistc1 = dlistc1->next, dlistc2 = dlistc2->next) { user_info_t* info = dlist->data; GtkObject* adj; GtkToggleButton* button; GtkEntry* entry; adj = dlistl1->data; info->max[0] = (int)(GTK_ADJUSTMENT(adj)->value); adj = dlistl2->data; info->max[1] = (int)(GTK_ADJUSTMENT(adj)->value); entry = dlistd->data; info->limit[0] = extract_bytes(gtk_entry_get_text(entry)); entry = dlistu->data; info->limit[1] = extract_bytes(gtk_entry_get_text(entry)); button = dlistc1->data; info->ignore_global[0] = gtk_toggle_button_get_active(button); button = dlistc2->data; info->ignore_global[1] = gtk_toggle_button_get_active(button); } on_button_band_cancel2_clicked(button, user_data); } static void get_special(user_info_t* info, GList** list) { if (!user_info_is_default(info)) *list = g_list_prepend(*list, info); } gint user_info_comp_func(gconstpointer a, gconstpointer b) { const user_info_t* info1 = a; const user_info_t* info2 = b; if (!info1) return (info2 != NULL); if (!info2) return -1; return g_strcasecmp(info1->nick, info2->nick); } void create_bandman_win() { GtkWidget *bandman_win; GtkWidget *frame; GtkWidget *vbox1; GtkWidget *vbox2; GtkWidget *hbox; GtkWidget *separator; GtkWidget *button; GtkWidget *entry; char str[1024]; GList* dlist; long limit; GtkWidget* label; GList* adj_list1 = NULL; GList* adj_list2 = NULL; GList* e_list1 = NULL; GList* e_list2 = NULL; GList* c_list1 = NULL; GList* c_list2 = NULL; GtkObject* adj; GList* user_list = NULL; GtkWidget* sw; user_info_foreach((UserInfoFunc)get_special, &user_list); user_list = g_list_sort(user_list, (GCompareFunc)user_info_comp_func); if (global.down_width.limit > global.up_width.limit) limit = global.down_width.limit*2; else limit = global.up_width.limit*2; bandman_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(bandman_win), "Special Users"); gtk_window_set_default_size(GTK_WINDOW (bandman_win), -1, 450); /* gtk_signal_connect(GTK_OBJECT(bandman_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL); */ vbox1 = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(bandman_win), vbox1); gtk_container_set_border_width(GTK_CONTAINER (vbox1), 10); label = gtk_label_new("Users with special transfer settings"); gtk_box_pack_start(GTK_BOX(vbox1), label, FALSE, FALSE, 10); separator = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox1), separator, FALSE, FALSE, 0); /////////// sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(vbox1), sw, TRUE, TRUE, 0); vbox2 = gtk_vbox_new(FALSE, 5); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(sw), vbox2); gtk_container_set_border_width(GTK_CONTAINER(vbox2), 5); gtk_viewport_set_shadow_type (GTK_VIEWPORT(GTK_BIN(sw)->child), GTK_SHADOW_NONE); for (dlist = user_list; dlist; dlist = dlist->next) { user_info_t* info = dlist->data; GtkWidget* table; GtkWidget* check; GtkWidget* spin; table = gtk_table_new(2, 2, FALSE); gtk_box_pack_start(GTK_BOX(vbox2), table, FALSE, FALSE, 0); gtk_table_set_col_spacings(GTK_TABLE(table), 5); label = gtk_label_new(info->nick); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 6, 0, 1, GTK_FILL, GTK_FILL, 0, 0); /// label = gtk_label_new(""); gtk_widget_set_usize(label, 20, -2); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); label = gtk_label_new("Download limit"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); adj = gtk_adjustment_new(info->max[0], -1, 1000, 1, 10, 10); spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0); gtk_table_attach(GTK_TABLE(table), spin, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0); adj_list1 = g_list_append(adj_list1, adj); label = gtk_label_new("bandwidth limit"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), print_bytes(str, info->limit[0])); gtk_widget_set_usize(entry, 100, -2); gtk_table_attach(GTK_TABLE(table), entry, 4, 5, 1, 2, GTK_FILL, GTK_FILL, 0, 0); e_list1 = g_list_append(e_list1, entry); check = gtk_check_button_new_with_label("ignore global limit"); gtk_table_attach(GTK_TABLE(table), check, 5, 6, 1, 2, GTK_FILL, GTK_FILL, 0, 0); if (info->ignore_global[0]) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE); c_list1 = g_list_append(c_list1, check); /// label = gtk_label_new(""); gtk_widget_set_usize(label, 20, -2); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); label = gtk_label_new("Upload limit"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_widget_set_usize(label, 20, -2); gtk_table_attach(GTK_TABLE(table), label, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); adj = gtk_adjustment_new(info->max[1], -1, 1000, 1, 10, 10); spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0); gtk_table_attach(GTK_TABLE(table), spin, 2, 3, 2, 3, GTK_FILL, GTK_FILL, 0, 0); adj_list2 = g_list_append(adj_list2, adj); label = gtk_label_new("bandwidth limit"); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_widget_set_usize(label, 20, -2); gtk_table_attach(GTK_TABLE(table), label, 3, 4, 2, 3, GTK_FILL, GTK_FILL, 0, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), print_bytes(str, info->limit[1])); gtk_widget_set_usize(entry, 100, -2); gtk_table_attach(GTK_TABLE(table), entry, 4, 5, 2, 3, GTK_FILL, GTK_FILL, 0, 0); e_list2 = g_list_append(e_list2, entry); check = gtk_check_button_new_with_label("ignore global"); gtk_table_attach(GTK_TABLE(table), check, 5, 6, 2, 3, GTK_FILL, GTK_FILL, 0, 0); if (info->ignore_global[1]) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE); c_list2 = g_list_append(c_list2, check); } gtk_object_set_data(GTK_OBJECT(bandman_win), "info_list", user_list); gtk_object_set_data(GTK_OBJECT(bandman_win), "adj_list1", adj_list1); gtk_object_set_data(GTK_OBJECT(bandman_win), "adj_list2", adj_list2); gtk_object_set_data(GTK_OBJECT(bandman_win), "e_list1", e_list1); gtk_object_set_data(GTK_OBJECT(bandman_win), "e_list2", e_list2); gtk_object_set_data(GTK_OBJECT(bandman_win), "c_list1", c_list1); gtk_object_set_data(GTK_OBJECT(bandman_win), "c_list2", c_list2); ///////////////////////// separator = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox1), separator, FALSE, FALSE, 0); ///////////////////////// frame = gtk_frame_new(NULL); gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0); gtk_widget_set_usize(frame, -2, 41); gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_IN); hbox = gtk_hbox_new(TRUE, 5); gtk_widget_show(hbox); gtk_container_add(GTK_CONTAINER (frame), hbox); gtk_container_set_border_width(GTK_CONTAINER (hbox), 5); button = gtk_button_new_with_label("Ok"); gtk_widget_show(button); gtk_box_pack_start(GTK_BOX (hbox), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "clicked", on_button_band_ok2_clicked, bandman_win); button = gtk_button_new_with_label("Cancel"); gtk_widget_show(button); gtk_box_pack_start(GTK_BOX (hbox), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "clicked", on_button_band_cancel2_clicked, bandman_win); gtk_widget_show_all(bandman_win); } void on_button_percent_ok_clicked(GtkButton * button, gpointer user_data) { GtkWidget *temp; GtkObject *adj; adj = user_data; if (!adj) return; global.limit.download_percent = (int)(GTK_ADJUSTMENT(adj)->value); temp = lookup_widget(GTK_WIDGET(button), "win"); on_button_band_cancel_clicked(button, temp); } static void create_percent_win() { GtkWidget *win; GtkWidget *frame; GtkWidget *vbox175; GtkWidget *vbox176; GtkWidget *hbox; GtkWidget *label; GtkWidget *hseparator34; GtkWidget *frame296; GtkWidget *hbox634; GtkWidget *button275; GtkWidget *button276; GtkWidget *hscale1; GtkObject *adj; win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_object_set_data(GTK_OBJECT(win), "win", win); gtk_window_set_title(GTK_WINDOW(win), "Dynamic Upload limit"); gtk_window_set_default_size(GTK_WINDOW(win), 500, -1); gtk_window_set_policy(GTK_WINDOW(win), FALSE, FALSE, FALSE); frame = gtk_frame_new(NULL); gtk_widget_show(frame); gtk_container_add(GTK_CONTAINER(win), frame); gtk_container_set_border_width(GTK_CONTAINER(frame), 5); vbox175 = gtk_vbox_new(FALSE, 5); gtk_widget_show(vbox175); gtk_container_add(GTK_CONTAINER(frame), vbox175); gtk_container_set_border_width(GTK_CONTAINER(vbox175), 5); vbox176 = gtk_vbox_new(FALSE, 5); gtk_widget_show(vbox176); gtk_box_pack_start(GTK_BOX(vbox175), vbox176, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(vbox176), hbox, FALSE, FALSE, 0); label = gtk_label_new("Setup value the upload limit should be reduced with the current download bandwidth"); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); hbox = gtk_hbox_new(FALSE, 5); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(vbox176), hbox, FALSE, FALSE, 0); adj = gtk_adjustment_new (global.limit.download_percent, 0, 100, 1, 1, 0); hscale1 = gtk_hscale_new (GTK_ADJUSTMENT (adj)); gtk_widget_show (hscale1); gtk_box_pack_start (GTK_BOX (hbox), hscale1, TRUE, TRUE, 0); gtk_scale_set_draw_value (GTK_SCALE (hscale1), TRUE); gtk_scale_set_digits (GTK_SCALE (hscale1), 0); hseparator34 = gtk_hseparator_new(); gtk_widget_show(hseparator34); gtk_box_pack_start(GTK_BOX(vbox175), hseparator34, FALSE, FALSE, 0); frame296 = gtk_frame_new(NULL); gtk_widget_show(frame296); gtk_box_pack_start(GTK_BOX(vbox175), frame296, FALSE, FALSE, 0); gtk_widget_set_usize(frame296, -2, 41); gtk_frame_set_shadow_type(GTK_FRAME(frame296), GTK_SHADOW_IN); hbox634 = gtk_hbox_new(TRUE, 5); gtk_widget_show(hbox634); gtk_container_add(GTK_CONTAINER(frame296), hbox634); gtk_container_set_border_width(GTK_CONTAINER(hbox634), 5); button275 = gtk_button_new_with_label("Ok"); gtk_widget_show(button275); gtk_box_pack_start(GTK_BOX(hbox634), button275, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button275), "clicked", on_button_percent_ok_clicked, adj); button276 = gtk_button_new_with_label("Cancel"); gtk_widget_show(button276); gtk_box_pack_start(GTK_BOX(hbox634), button276, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button276), "clicked", on_button_band_cancel_clicked, win); gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL); gtk_widget_show(win); return; } void upload_update_speed(user_info_t* userinfo) { GtkCList *clist; socket_t *socket; transfer_t* trans; int i1; if (!userinfo) return; clist = GTK_CLIST(lookup_widget(global.win, "transfer_up")); gtk_clist_freeze(clist); for (i1 = 0; i1 < clist->rows; i1++) { socket = gtk_clist_get_row_data(clist, i1); if (socket->type == S_UPLOAD) { trans = TRANS(socket->data); if (trans->user_info != userinfo) continue; upload_update(socket); } else if (socket->type == S_SHARE) { trans = TRANS(socket->data); if (trans->user_info != userinfo) continue; share_update(socket); } } gtk_clist_thaw(clist); } file_segment_t* file_segment_new(long start, long stop) { file_segment_t* result; result = g_malloc(sizeof(*result)); result->start = start; result->size = 0; result->stop = stop; result->flags = 0; result->merge_cnt = 0; result->socket = NULL; return result; } void file_segment_destroy(file_segment_t* part) { g_free(part); } file_segment_t* update_best(file_segment_t* old_prev, file_segment_t* prev, file_segment_t* current, long size, long* max, long* stop) { long pos1; long size1; long pos2; long size2; long min; long new_size; if (prev) { pos1 = prev->start; size1 = prev->size; } else { pos1 = 0; size1 = 0; } if (current) { pos2 = current->start; size2 = current->size; } else { pos2 = size; size2 = 0; } new_size = pos2 - pos1 - size1; if (!prev || !prev->socket) min = 0; else min = 1024*global.limit.min_segment_size; if (new_size <= min) return old_prev; if (*max == 0 || // none found yet or previous is downloading (old_prev && old_prev->socket)) { if (min == 0 || new_size > *max) { *stop = pos2; *max = new_size; return prev; } else return old_prev; } else { return old_prev; } } // return *stop == 0, if no free part file_segment_t* file_segment_find_free(resume_t* resume, long* stop) { GList* dlist; file_segment_t* segment1 = NULL; file_segment_t* segment2; long max_space = 0; file_segment_t* result = NULL; GList* parts = resume->parts; if (resume->flags & RESUME_INACTIVE) { *stop = 0; return NULL; } if (!parts) { if (!resume->comp_size) { g_warning("resume has unknown size but no segments"); } *stop = resume->comp_size; return NULL; } *stop = 0; if (!resume->comp_size) { segment2 = parts->data; *stop = segment2->start+segment2->size+10000; result = segment2; } else { for (dlist = parts; dlist; dlist = dlist->next) { segment2 = dlist->data; result = update_best(result, segment1, segment2, resume->comp_size, &max_space, stop); segment1 = segment2; segment2 = NULL; } result = update_best(result, segment1, segment2, resume->comp_size, &max_space, stop); } if (*stop == 0) resume->flags &= ~RESUME_FREE_SEGMENT; return result; } void file_segment_attach_to_download(socket_t* socket, file_segment_t* segment) { download_t* download = socket->data; if (!download) return; download->resume->active++; download->csegment = g_list_find(download->resume->parts, segment); if (!download->csegment) g_warning("could not find segment"); segment->socket = socket; transfer_reset(TRANS(download), segment->start+segment->size); download->resume->needs_update = 1; } file_segment_t* file_segment_create_after(resume_t* resume, file_segment_t* segment, long stop) { long start; int i1; file_segment_t* old_seg; if (resume->active < 0) { g_warning("resume->active < 0"); } if (!segment) { segment = file_segment_new(0, stop); resume->parts = g_list_prepend(resume->parts, segment); #ifdef TRANSFER_DEBUG printf("first segment: %d %d %d\n", segment->start, segment->size, segment->stop); #endif } else { // insert = g_list_find(resume->parts, segment); // if (!insert) return 0; i1 = g_list_index(resume->parts, segment); if (i1 < 0) { g_warning("segment not found"); return 0; } if (segment->socket) { // downloading start = ((segment->start + segment->size)/3*2 + stop/3); if (stop == resume->comp_size && start > segment->start + segment->size + global.limit.max_seek_add*1024*1024) start = segment->start + segment->size + global.limit.max_seek_add*1024*1024; old_seg = segment; segment = file_segment_new(start, stop); #ifdef TRANSFER_DEBUG printf("new segment: %d %d %d\n", segment->start, segment->size, segment->stop); #endif resume->parts = g_list_insert(resume->parts, segment, i1+1); /////// // adjusting the stop position here isnt really neccessary, // cause its done automaticlally in download_get_input(). old_seg->stop = start; #ifdef ADVANCED_CONNECTION { download_t* download = old_seg->socket->data; if (download->advanced == 1) download_send_stop(old_seg->socket); } #endif /////// } else { start = segment->start + segment->size; segment->stop = start; segment = file_segment_new(start, stop); segment->size = -RESUME_CHECK_LENGTH; #ifdef TRANSFER_DEBUG printf("new segment: %d %d %d\n", segment->start, segment->size, segment->stop); #endif resume->parts = g_list_insert(resume->parts, segment, i1+1); } } return segment; } void file_segment_remove(resume_t* resume, file_segment_t* segment) { GList* dlist; dlist = g_list_find(resume->parts, segment); if (dlist) { resume->parts = g_list_remove(resume->parts, segment); #ifdef TRANSFER_DEBUG printf("remove segment: %d %d %d\n", segment->start, segment->size, segment->stop); #endif if (segment->size > 0) resume->inc_size -= segment->size; } file_segment_destroy(segment); } char* file_segment_print(GList* parts) { file_segment_t* segment; static char result[2048] = ""; char temp[1024] = ""; GList* dlist; *result = 0; for (dlist = parts; dlist; dlist = dlist->next) { segment = dlist->data; if (segment->size > 0) { sprintf(temp, "%d %d ", segment->start, segment->size); strcat(result, temp); } } return result; } void file_segment_merge(resume_t *resume, GList* segment) { file_segment_t* seg1; file_segment_t* seg2; seg2 = segment->data; if (segment->prev) { seg1 = segment->prev->data; if (!(seg1->flags & PART_CHECK_ERROR) && !seg1->socket && seg1->start+seg1->size == seg2->start) { #ifdef RESUME_DEBUG printf("merging %d %d %d\n", seg1->start, seg1->size, seg1->stop); printf(" with %d %d %d\n", seg2->start, seg2->size, seg2->stop); #endif seg2->start = seg1->start; seg2->size += seg1->size; seg2->merge_cnt += seg1->merge_cnt + 1; resume->parts = g_list_remove(resume->parts, seg1); #ifdef RESUME_DEBUG printf("result1 %d %d %d\n", seg2->start, seg2->size, seg2->stop); #endif file_segment_destroy(seg1); } } if (segment->next) { seg1 = segment->next->data; if (!(seg2->flags & PART_CHECK_ERROR) && !seg1->socket && seg2->start+seg2->size == seg1->start) { #ifdef RESUME_DEBUG printf("merging %d %d %d\n", seg1->start, seg1->size, seg1->stop); printf(" with %d %d %d\n", seg2->start, seg2->size, seg2->stop); #endif seg2->size += seg1->size; if (seg1->flags & PART_CHECK_ERROR) seg2->flags |= PART_CHECK_ERROR; seg2->merge_cnt += seg1->merge_cnt + 1; resume->parts = g_list_remove(resume->parts, seg1); #ifdef RESUME_DEBUG printf("result2 %d %d %d\n", seg2->start, seg2->size, seg2->stop); #endif file_segment_destroy(seg1); } } } net_user_t* download_find_net_user(download_t* download, net_t* net, char* user) { GList* dlist; net_user_t* nu; // printf("finding %p\n", net); for (dlist = download->nets; dlist; dlist = dlist->next) { nu = dlist->data; // printf(" -- %p\n", nu->net); if (nu->net == net && !strcasecmp(nu->user, user)) return nu; } return NULL; } void download_add_net(download_t* download, net_t* net, char* user) { net_user_t* nu; nu = g_malloc(sizeof(*nu)); nu->net = net; nu->user = g_strdup(user); download->nets = g_list_append(download->nets, nu); } void upload_remove_access(access_t* access) { GList* dlist; socket_t* socket; upload_t* upload; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket || (socket->type != S_UPLOAD)) continue; upload = socket->data; if (!upload) continue; if (upload->access == access) { upload->access = NULL; upload->node = NULL; } } } void transfer_cancel_running() { GList* dlist; socket_t* socket; GList* uploads = NULL; GList* downloads = NULL; for (dlist = global.sockets; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket) continue; if (socket->fd == -1) continue; if (socket->type == S_UPLOAD) { uploads = g_list_prepend(uploads, socket); } else if (socket->type == S_DOWNLOAD) { downloads = g_list_prepend(downloads, socket); } } for (dlist = uploads; dlist; dlist = dlist->next) { socket = dlist->data; socket_end(socket, S_DELETE); } g_list_free(uploads); for (dlist = downloads; dlist; dlist = dlist->next) { socket = dlist->data; socket_end(socket, S_CANCELED); } g_list_free(downloads); }