/* 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 "lopster.h" #include "callbacks.h" #include "connection.h" #include "handler.h" #include "global.h" #include "search.h" #include "transfer.h" #include "scheme.h" #include "resume.h" #include "share2.h" #include "string_list.h" #include "support.h" #include "whois.h" #include "utils.h" char *search_arg(char *data); void info_dialog(char *text); typedef struct { char* filename; GtkBox* box; GtkToggleButton* check; GtkProgressBar* progress; GtkLabel* action; long size; int last_progress; int fd; GList* segments; long current_pos; long start_found; } dead_t; static GList* DeadFiles = NULL; static GtkWidget* ScanWin = NULL; static int ScanIdle = -1; //#define RESUME_DEBUG char *get_search_string(char *str) { static char result[1024]; char *pos; pos = strrchr(str, '.'); if (pos) *pos = 0; *result = 0; pos = search_arg(str); while (pos) { if (strlen(pos) != 4 || pos[0] != 'L' || !isdigit(pos[1]) || !isdigit(pos[2]) || !isdigit(pos[3])) { if (*result) strcat(result, " "); strcat(result, pos); } pos = search_arg(NULL); } return result; } resume_t *resume_new(long access) { resume_t *resume; resume_t *resume2; GList* dlist; int cnt; resume = g_malloc(sizeof(resume_t)); resume->filename = NULL; resume->dirname = NULL; resume->comp_size = 0; resume->search = NULL; resume->active = 0; resume->flags = RESUME_FREE_SEGMENT; resume->search_string = NULL; resume->downloads = NULL; resume->last_access = access; resume->tree_no = -1; resume->node = NULL; resume->is_dcc = 0; resume->parts = NULL; resume->inc_size = 0; resume->needs_update = 0; cnt = 0; for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume2 = dlist->data; if (resume2->last_access < access) break; cnt++; } global.incomplete = g_list_insert(global.incomplete, resume, cnt); return resume; } void resume_destroy(resume_t * resume) { if (!resume) return; if (resume->filename) g_free(resume->filename); if (resume->dirname) g_free(resume->dirname); if (resume->search) resume_remove_search(resume); if (resume->search_string) g_free(resume->search_string); g_list_free(resume->downloads); global.incomplete = g_list_remove(global.incomplete, resume); resume_save(NULL); g_free(resume); } void resume_load(char *fname, int import) { FILE *fd; resume_t *resume = NULL; char line[2048]; char *filename; char *size; char *dirname; char *user; char *org_file; char *search; char *last_access; long long_access; char *short_file; char* status; int have_incomplete; unsigned long start; unsigned long length; char* temp1; char* temp2; char* temp3; char* temp4; file_segment_t* segment; struct stat st; GList* link; int cnt = 0; #ifdef RESUME_DEBUG printf("reading [%s][%s]\n", fname, global.incomplete_path?global.incomplete_path:"(null)"); #endif if (!global.incomplete_path || !create_dir(global.incomplete_path)) { if (import) { client_message("Error", "Could not import incomplete list: no valid incomplete folder"); return; } have_incomplete = 0; } else have_incomplete = 1; if ((fd = fopen(fname, "r")) == NULL) return; while (mfgets(line, sizeof(line), fd)) { if (line[0] == '-') { temp1 = arg(line+1, 0); temp2 = arg(NULL, 0); temp3 = arg(NULL, 0); temp4 = arg(NULL, 0); if (!temp2 || !resume) continue; start = strtoul(temp1, NULL, 10); length = strtoul(temp2, NULL, 10); cnt++; // increase the segment counter if (length < 1000) continue; segment = file_segment_new(start, start+length); segment->size = length; if (temp3) segment->flags = atoi(temp3); if (temp4) segment->merge_cnt = atoi(temp4); resume->parts = g_list_append(resume->parts, segment); resume->inc_size += length; #ifdef RESUME_DEBUG printf("part %ld %ld %d\n", start, length, segment->flags); #endif link = g_list_find(resume->parts, segment); if (link) file_segment_merge(resume, link); } else { filename = arg(line, 2); short_file = get_file_name(filename); size = arg(NULL, 2); dirname = arg(NULL, 2); user = arg(NULL, 2); org_file = arg(NULL, 2); search = arg(NULL, 2); last_access = arg(NULL, 2); status = arg(NULL, 2); if (!search) continue; if (!status) { // backward compatible to 1.0.1 // user and org_file tag removed status = search; last_access = org_file; search = user; } if (resume_search_short_file(short_file)) continue; if (resume) { // backward compatible, create local existent segment if (cnt == 0) { if (!resume->parts && stat(resume->filename, &st) >= 0 && st.st_size > 1000) { segment = file_segment_new(0, st.st_size); segment->size = st.st_size; resume->parts = g_list_append(resume->parts, segment); resume->inc_size = st.st_size; } } resume_show(resume); } long_access = strtoul(last_access, NULL, 10); resume = resume_new(long_access); cnt = 0; // reset the segment counter; if (have_incomplete && import) resume->filename = g_strdup_printf("%s%c%s", global.incomplete_path, DIR_SEP, short_file); else resume->filename = g_strdup(filename); resume->comp_size = strtoul(size, NULL, 10); resume->dirname = g_strdup(dirname); if (*search) resume->search_string = g_strdup(search); else resume->search_string = NULL; resume->flags = atoi(status); resume->flags |= RESUME_FREE_SEGMENT; } } if (resume) { if (cnt == 0) { if (!resume->parts && stat(resume->filename, &st) >= 0 && st.st_size > 1000) { segment = file_segment_new(0, st.st_size); segment->size = st.st_size; resume->parts = g_list_append(resume->parts, segment); resume->inc_size = st.st_size; } } resume_show(resume); } fclose(fd); if (import) resume_save(NULL); } // function patched by saturn_de int resume_save(gpointer data ATTR_UNUSED) { GList *dlist; GList *dlist2; resume_t *resume; char *fname; char *fname_new; FILE *fd; long start; long size; file_segment_t* segment; fname = g_strdup_printf("%s%cincomplete.list", global.options.config_dir, DIR_SEP); fname_new = g_strdup_printf("%s%cincomplete.list.new", global.options.config_dir, DIR_SEP); if ((fd = fopen(fname_new, "w")) == NULL) { g_warning("Could not write [%s]\n", fname); g_free(fname); g_free(fname_new); return 1; } for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = dlist->data; if (resume->flags & RESUME_FINISHED) continue; if (resume->is_dcc) continue; qfprintf(fd, "%S %ld %S %S %lu %d\n", resume->filename, resume->comp_size, (resume->dirname) ? (resume->dirname) : "", (resume->search_string) ? (resume->search_string) : "", resume->last_access, resume->flags & (RESUME_DEACTIVATED|RESUME_DONT_MSOURCE)); start = size = -1; segment = NULL; if (resume->parts) { for (dlist2 = resume->parts; dlist2; dlist2 = dlist2->next) { segment = dlist2->data; fprintf(fd, "- %d %d %d %d\n", segment->start, segment->size, segment->flags&PART_CHECK_ERROR, segment->merge_cnt); } } else { fprintf(fd, "- 0 0 0 0\n"); } } if (!fsync(fileno(fd)) && !ferror(fd)) { fclose(fd); rename(fname_new, fname); } else { fclose(fd); g_warning("Could not write [%s]\n", fname); } g_free(fname); g_free(fname_new); return 1; } int resume_insert_file(resume_t * resume, file_t * file) { socket_t *socket; transfer_t *trans; int mtype; /* media types have to match, if they are MIME_NONE then * then suffixes have to match. * Necessary if downloading multi volume archives with same * size, same basename, but different suffixes */ mtype = mtype_get(resume->filename); if (mtype != file->media_type) return 0; if (mtype == MEDIA_NONE) { char* suf1 = strrchr(file->shortname, '.'); char* suf2 = strrchr(resume->filename, '.'); if (suf1 && !suf2) return 0; if (!suf1 && suf2) return 0; if (suf1 && suf2 && strcmp(suf1, suf2)) return 0; } socket = download_create(file, resume, NULL, NULL, 0); if (!socket || !socket->data) return 0; trans = TRANS(socket->data); if (!transfer_in_progress(trans) && (socket->timer == -1) && (trans->status != S_REMOTE) && (trans->status != S_QUEUED) && (trans->status != S_CANCELED) && // dont start canceled (trans->status != S_FINISHED)) { download_status_set(socket, S_QUEUED); } return 1; } resume_t* resume_search_short_file(char* filename) { GList *dlist; resume_t *resume; char *fname; for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = dlist->data; fname = get_file_name(resume->filename); if (!strcmp(fname, filename)) return resume; } return NULL; } resume_t *resume_search_long_file(char *filename) { GList *dlist; resume_t *resume; for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = dlist->data; if (!strcmp(resume->filename, filename)) return resume; } return NULL; } resume_t *resume_search_file(file_t * file) { GList *dlist; resume_t *resume; char *pos; for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = (resume_t *) (dlist->data); pos = get_file_name(resume->filename); if (!strcmp(file->filename, pos) && (file->size == resume->comp_size)) return resume; } return NULL; } GList *resume_search_size(long size) { GList *dlist; resume_t *resume; GList* result = NULL; for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = dlist->data; if (!resume->comp_size || size == resume->comp_size) result = g_list_append(result, resume); } return result; } GList *resume_search_size_real(long size) { GList *dlist; resume_t *resume; GList* result = NULL; for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = dlist->data; if (size == resume->comp_size) result = g_list_append(result, resume); } return result; } void resume_update_search(resume_t* resume, char* text) { char* pos; if (!resume || !resume->search) return; if (resume->search->pattern->include) g_free(resume->search->pattern->include); if (text && *text) { resume->search->pattern->include = g_strdup(text); } else { pos = g_strdup(get_file_name(resume->filename)); resume->search->pattern->include = g_strdup(get_search_string(pos)); g_free(pos); } } void resume_create_search(resume_t * resume) { search_t *search; search_pattern_t *pattern; search = search_new(); search->resume = 1; search->link = resume; pattern = search_pattern_new(); search->pattern = pattern; resume->search = search; resume_update_search(resume, resume->search_string); pattern->name = g_strdup(pattern->include); pattern->exclude = g_strdup(""); pattern->max_results = 0; pattern->destination = DEST_NAPSTER; if (resume->comp_size) pattern->size_lo = pattern->size_hi = resume->comp_size; else pattern->size_lo = resume->inc_size; pattern->media_type = MEDIA_NONE; } void resume_search(resume_t * resume, net_t* net) { if (!resume) return; if (resume->flags & RESUME_INACTIVE) return; if (!resume->search) resume_create_search(resume); search_queue(resume->search, net, 1); } void resume_search_all(net_t* net, int force) { resume_t *resume; GList *dlist; if (!force && !global.options.auto_search) return; if (net) { for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = dlist->data; resume_search(resume, net); } } else { for (dlist = global.net_active; dlist; dlist = dlist->next) { net = dlist->data; resume_search_all(net, force); } } } void resume_remove_search(resume_t * resume) { if (!resume->search) return; // remove files from resume if (resume->search) search_remove(resume->search); resume->search = NULL; resume->needs_update = 1; } static int resume_belongs_to(resume_t * resume) { int class; if (!resume) return -1; // should never happen if (resume->active > 0 || (resume->flags & RESUME_FINISHED)) class = 0; else if (resume->flags & RESUME_DEACTIVATED) class = 3; else if (resume_has_potentials(resume)) class = 1; else class = 2; class = global.dl_layout.transfer_position[class]; return class; } void resume_show(resume_t * resume) { GtkCTree *ctree; int tree_no; char *pos; GtkCTreeNode *node; GList* dlist; socket_t* socket; int at_top = 0; GtkCTreeNode* sibling; GtkCList* clist; if (!resume) return; tree_no = resume_belongs_to(resume); if (resume->tree_no >= 0) { if (resume->tree_no < tree_no) at_top = 1; if (resume->tree_no != tree_no) resume_hide(resume); else return; } pos = get_file_name(resume->filename); strcpy(tstr[0], pos); tstr[1][0] = 0; tstr[2][0] = 0; tstr[3][0] = 0; tstr[4][0] = 0; tstr[5][0] = 0; tstr[6][0] = 0; tstr[7][0] = 0; ctree = DownloadTree[tree_no]; clist = GTK_CLIST(ctree); if (at_top == 1) sibling = GTK_CTREE_NODE (clist->row_list); else sibling = NULL; node = gtk_ctree_insert_node(ctree, NULL, sibling, list, 5, NULL, NULL, NULL, NULL, FALSE, FALSE); gtk_ctree_node_set_row_data(ctree, node, resume); resume->tree_no = tree_no; resume->node = node; for (dlist = resume->downloads; dlist; dlist = dlist->next) { socket = dlist->data; download_show(socket); } resume_update(resume); } // intern function static int resume_update_resume(resume_t * resume) { GtkCTree *ctree; GtkCTreeNode *node; char text[1024]; GdkPixmap *pixmap = NULL; GdkBitmap *bitmap = NULL; transfer_t* trans; GList* dlist; int timeleft; double rate; int cnt; socket_t* socket; if (!resume) return 1; node = resume->node; if (resume->tree_no < 0 || !node) { g_warning("Resume not shown"); return 1; } ctree = DownloadTree[resume->tree_no]; // col 0: filename -> skip // col 1: filesize if (resume->comp_size) sprintf(text, "%s [%.1f%%]", print_size(tstr[0], resume->comp_size), (double)resume->inc_size/(double)resume->comp_size*100); else sprintf(text, "%s", print_size(tstr[0], resume->inc_size)); gtk_ctree_node_set_text(ctree, node, 1, text); // col 2: user -> print number of results if (!resume->search) { sprintf(text, "Not Searched"); } else { sprintf(text, "%d results", g_list_length(resume->downloads)); } gtk_ctree_node_set_text(ctree, node, 2, text); // col 3: speed -> print number of active if (resume->flags & RESUME_FINISHED) { sprintf(text, "Finished"); } else if (resume->flags & RESUME_DEACTIVATED) { sprintf(text, "Deactivated"); } else if (resume->active > 0) { sprintf(text, "%d active", resume->active); } else if (resume->search && resume->search->net_info) { sprintf(text, "%d servers remaining", g_list_length(resume->search->net_info)); } else { sprintf(text, "-"); } gtk_ctree_node_set_text(ctree, node, 3, text); // col 4: status/progress if (resume->parts) { gtk_ctree_node_get_pixmap(ctree, node, 4, &pixmap, &bitmap); pixmap = resume_draw_progress(GTK_CLIST(ctree), pixmap, resume, GTK_CLIST(ctree)->column[4].width); gtk_ctree_node_set_pixmap(ctree, node, 4, pixmap, NULL); } else { gtk_ctree_node_set_text(ctree, node, 4, "not existent"); } // col 5: rate // timeleft = 0; rate = 0.; cnt = 0; for (dlist = resume->downloads; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket) continue; trans = TRANS(socket->data); if (trans->status != S_DOWNLOADING) continue; rate += trans->rate; cnt++; // if (trans->timeleft < timeleft) // timeleft = trans->timeleft; } if (cnt > 0) { print_speed(text, (int) rate, 1); down_speed_pixs(rate, &pixmap, &bitmap); gtk_ctree_node_set_pixtext(ctree, node, 5, text, 5, pixmap, bitmap); } else { gtk_ctree_node_set_text(ctree, node, 5, ""); } // col 6: timeleft if (cnt > 0) { if (rate > 0) { timeleft = - (int) ((resume->comp_size - resume->inc_size) / rate); print_time_unit(text, timeleft); } else { sprintf(text, "stalled"); } } else { *text = 0; } gtk_ctree_node_set_text(ctree, node, 6, text); return 1; } void resume_update_resume2(resume_t * resume) { GtkCTree *ctree = DownloadTree[resume->tree_no]; GtkCTreeNode *node = resume->node; char text[1024]; GdkPixmap *pixmap = NULL; GdkBitmap *bitmap = NULL; time_t tim; int temp; if (!resume) return; // col 0: filename -> skip // col 1: filesize if (resume->comp_size) sprintf(text, "%s [%.1f%%]", print_size(tstr[0], resume->comp_size), (double)resume->inc_size/(double)resume->comp_size*100); else sprintf(text, "%s", print_size(tstr[0], resume->inc_size)); gtk_ctree_node_set_text(ctree, node, 1, text); // col 2: user -> print info if (!resume->search) { sprintf(text, "Not Searched"); } else { sprintf(text, "%d results", g_list_length(resume->downloads)); } temp = strlen(text); if (resume->flags & RESUME_FINISHED) { *(text+temp) = ' '; sprintf(text+temp+1, "[Finished]"); } else if (resume->flags & RESUME_DEACTIVATED) { *(text+temp) = ' '; sprintf(text+temp+1, "[Deactivated]"); } else if (resume->active > 0) { *(text+temp) = ' '; sprintf(text+temp+1, "[%d active]", resume->active); } else if (resume->search && resume->search->net_info) { *(text+temp) = ' '; sprintf(text+temp+1, "[%d servers remaining]", g_list_length(resume->search->net_info)); } gtk_ctree_node_set_text(ctree, node, 2, text); // col 3: status if (resume->parts) { gtk_ctree_node_get_pixmap(ctree, node, 3, &pixmap, &bitmap); pixmap = resume_draw_progress(GTK_CLIST(ctree), pixmap, resume, GTK_CLIST(ctree)->column[3].width); gtk_ctree_node_set_pixmap(ctree, node, 3, pixmap, NULL); } else { gtk_ctree_node_set_text(ctree, node, 3, "not existent"); } // col 4: life time tim = resume_time_of_death(resume); if (tim == 0) strcpy(text, "Never"); else if (tim == 1) strcpy(text, "Now"); else { strcpy(text, ctime(&tim)); text[strlen(text) - 1] = 0; } gtk_ctree_node_set_text(ctree, node, 4, text); return; } static void resume_set_colors(resume_t* resume) { style_t *style; GtkCTree *ctree; GtkCTreeNode *node; node = resume->node; if (resume->tree_no < 0 || !node) return; ctree = DownloadTree[resume->tree_no]; if (resume->active > 0) { style = style_get(global.scheme, "transfer_running"); if (style) { gtk_ctree_node_set_background(ctree, node, style->back); gtk_ctree_node_set_foreground(ctree, node, style->fore); } } else if (resume_has_potentials(resume)) { style = style_get(global.scheme, "transfer_waiting"); if (style) { gtk_ctree_node_set_background(ctree, node, style->back); gtk_ctree_node_set_foreground(ctree, node, style->fore); } } else { gtk_ctree_node_set_background(ctree, node, NULL); gtk_ctree_node_set_foreground(ctree, node, NULL); } } void resume_update(resume_t * resume) { if (!resume) return; if (resume->tree_no < 0 || !resume->node) { #ifdef RESUME_DEBUG g_warning("resume_update(): resume not shown\n"); #endif return; } if (resume_belongs_to(resume) != resume->tree_no) { resume_show(resume); return; } if (resume->tree_no == 0) { resume_update_resume(resume); } else { resume_update_resume2(resume); } resume_set_colors(resume); resume->needs_update = 0; } void resume_cancel(resume_t * resume) { GList *dlist; socket_t *socket; transfer_t *trans; if (!resume) return; #ifdef RESUME_DEBUG printf("stopping r:%p\n", resume); #endif // first remove resume link from unactive transfers for (dlist = resume->downloads; dlist; dlist = dlist->next) { socket = dlist->data; if (!socket) return; trans = TRANS(socket->data); if (!trans) return; if (trans->status == S_QUEUED || trans->status == S_REMOTE || transfer_in_progress(trans) || socket->timer != -1) { socket_end(socket, S_CANCELED); } } resume_update(resume); } void resume_remove(resume_t * resume) { socket_t *socket; if (!resume) return; // resume_cancel(resume); if ((resume->flags & RESUME_FINISHED) == 0) { // printf("delete = %s\n", resume->filename); unlink(resume->filename); } while (resume->downloads) { socket = resume->downloads->data; socket_destroy(socket, S_DELETE); } // removing from visual list resume_hide(resume); resume_destroy(resume); } void resume_freeze(resume_t * resume) { if (resume->flags & (RESUME_INACTIVE)) return; resume_cancel(resume); resume->flags |= RESUME_DEACTIVATED; resume_update(resume); } void resume_thaw(resume_t * resume) { if ((resume->flags & RESUME_DEACTIVATED) == 0) return; resume->flags &= ~RESUME_DEACTIVATED; resume_update(resume); } int resume_timer(gpointer data ATTR_UNUSED) { resume_search_all(NULL, 0); if (global.options.resume_timeout < 30) global.options.resume_timeout = 30; if (global.resume_timer >= 0) gtk_timeout_remove(global.resume_timer); global.resume_timer = gtk_timeout_add(global.options.resume_timeout * 60 * 1000, resume_timer, NULL); return 1; } int resume_has_potentials(resume_t* resume) { socket_t *socket; download_t *download; transfer_t *trans; GList *dlist; int res = 0; if (!resume) return 0; for (dlist = resume->downloads; dlist; dlist = dlist->next) { socket = dlist->data; if (socket->timer != -1) res |= 1; download = socket->data; trans = TRANS(download); if (transfer_in_progress(trans)) res |= 1; if (trans->status == S_QUEUED && global.options.auto_resume) res |= 4; if (trans->status == S_PART) res |= 4; } return res; } time_t resume_time_of_death(resume_t* resume) { time_t value; long lsize; long lsize2; double per; lsize = resume->inc_size; lsize2 = resume->comp_size; if (!global.options.resume_abort[0]) return 0; if (lsize2) per = (double)lsize/(double)lsize2; else per = 1.0; value = (time_t)global.options.resume_abort[1]*24*60*60 + (time_t)((double)global.options.resume_abort[2]*24*60*60*per); if (resume->last_access + value <= global.current_time) { return 1; } else { return resume->last_access + value; } return 0; } void resume_remove_outdated() { GList* dlist; resume_t *resume; GList* result = NULL; for (dlist = global.incomplete; dlist; dlist = dlist->next) { resume = dlist->data; if (resume->flags & RESUME_FINISHED) { if (global.options.dl_autoremove & REMOVE_D_FINISHED) result = g_list_prepend(result, resume);; } else if (!resume->active && !resume_has_potentials(resume) && (resume_time_of_death(resume) == 1)) { result = g_list_prepend(result, resume);; } else if (!resume->search && global.net_active && global.options.auto_search) { resume_search(resume, NULL); } } for (dlist = result; dlist; dlist = dlist->next) { resume = dlist->data; resume_remove(resume); } g_list_free(result); } void resume_hide(resume_t * resume) { if (resume->tree_no < 0 || !resume->node) { #ifdef RESUME_DEBUG printf("resume_hide(): resume not shown\n"); #endif return; } gtk_ctree_remove_node(DownloadTree[resume->tree_no], resume->node); resume->tree_no = -1; resume->node = NULL; } GtkWidget* create_abort_win (void) { GtkWidget *abort_win; GtkWidget *frame324; GtkWidget *vbox192; GtkWidget *vbox193; GtkWidget *hbox686; GtkWidget *checkbutton69; GtkObject *spinbutton63_adj; GtkWidget *spinbutton63; GtkWidget *label1017; GtkWidget *entry122; GtkWidget *label1018; GtkObject *spinbutton64_adj; GtkWidget *spinbutton64; GtkWidget *label1016; GtkWidget *hseparator36; GtkWidget *frame325; GtkWidget *hbox685; GtkWidget *button318; GtkWidget *button319; abort_win = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_object_set_data (GTK_OBJECT (abort_win), "abort_win", abort_win); gtk_window_set_title (GTK_WINDOW (abort_win), "Resume Abort"); gtk_window_set_default_size (GTK_WINDOW (abort_win), 520, -1); frame324 = gtk_frame_new (NULL); gtk_widget_show (frame324); gtk_container_add (GTK_CONTAINER (abort_win), frame324); gtk_container_set_border_width (GTK_CONTAINER (frame324), 5); vbox192 = gtk_vbox_new (FALSE, 5); gtk_widget_show (vbox192); gtk_container_add (GTK_CONTAINER (frame324), vbox192); gtk_container_set_border_width (GTK_CONTAINER (vbox192), 5); vbox193 = gtk_vbox_new (FALSE, 6); gtk_widget_show (vbox193); gtk_box_pack_start (GTK_BOX (vbox192), vbox193, TRUE, TRUE, 0); hbox686 = gtk_hbox_new (FALSE, 5); gtk_widget_show (hbox686); gtk_box_pack_start (GTK_BOX (vbox193), hbox686, FALSE, FALSE, 0); checkbutton69 = gtk_check_button_new_with_label ("Keep incomplete files at most"); if (global.options.resume_abort[0]) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton69), TRUE); gtk_widget_show (checkbutton69); gtk_object_set_data (GTK_OBJECT (abort_win), "check", checkbutton69); gtk_box_pack_start (GTK_BOX (hbox686), checkbutton69, FALSE, FALSE, 0); spinbutton63_adj = gtk_adjustment_new (global.options.resume_abort[1], 0, 365*20, 1, 10, 10); gtk_object_set_data (GTK_OBJECT (abort_win), "adj2", spinbutton63_adj); spinbutton63 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton63_adj), 1, 0); gtk_widget_show (spinbutton63); gtk_box_pack_start (GTK_BOX (hbox686), spinbutton63, TRUE, TRUE, 0); label1017 = gtk_label_new ("+"); gtk_widget_show (label1017); gtk_box_pack_start (GTK_BOX (hbox686), label1017, FALSE, FALSE, 0); entry122 = gtk_entry_new (); gtk_widget_show (entry122); gtk_box_pack_start (GTK_BOX (hbox686), entry122, FALSE, FALSE, 0); gtk_widget_set_usize (entry122, 69, -2); gtk_entry_set_editable (GTK_ENTRY (entry122), FALSE); gtk_entry_set_text (GTK_ENTRY (entry122), "progress"); label1018 = gtk_label_new ("x"); gtk_widget_show (label1018); gtk_box_pack_start (GTK_BOX (hbox686), label1018, FALSE, FALSE, 0); spinbutton64_adj = gtk_adjustment_new (global.options.resume_abort[2], 0, 1000, 1, 10, 10); gtk_object_set_data (GTK_OBJECT (abort_win), "adj3", spinbutton64_adj); spinbutton64 = gtk_spin_button_new (GTK_ADJUSTMENT (spinbutton64_adj), 1, 0); gtk_widget_show (spinbutton64); gtk_box_pack_start (GTK_BOX (hbox686), spinbutton64, TRUE, TRUE, 0); label1016 = gtk_label_new ("days since last success"); gtk_widget_show (label1016); gtk_box_pack_start (GTK_BOX (hbox686), label1016, FALSE, FALSE, 0); hseparator36 = gtk_hseparator_new (); gtk_widget_show (hseparator36); gtk_box_pack_start (GTK_BOX (vbox192), hseparator36, FALSE, FALSE, 0); frame325 = gtk_frame_new (NULL); gtk_widget_show (frame325); gtk_box_pack_start (GTK_BOX (vbox192), frame325, FALSE, FALSE, 0); gtk_widget_set_usize (frame325, -2, 41); gtk_frame_set_shadow_type (GTK_FRAME (frame325), GTK_SHADOW_IN); hbox685 = gtk_hbox_new(TRUE, 5); gtk_widget_show (hbox685); gtk_container_add(GTK_CONTAINER(frame325), hbox685); gtk_container_set_border_width (GTK_CONTAINER (hbox685), 5); button318 = gtk_button_new_with_label("Ok"); gtk_widget_show (button318); gtk_box_pack_start (GTK_BOX (hbox685), button318, TRUE, TRUE, 0); button319 = gtk_button_new_with_label("Cancel"); gtk_widget_show (button319); gtk_box_pack_start (GTK_BOX (hbox685), button319, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(abort_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL); gtk_signal_connect(GTK_OBJECT(button318), "clicked", GTK_SIGNAL_FUNC(on_button318_clicked), (gpointer)abort_win); gtk_signal_connect(GTK_OBJECT(button319), "clicked", GTK_SIGNAL_FUNC(on_button319_clicked), (gpointer)abort_win); return abort_win; } void resume_saver_start() { if (global.resume_saver >= 0) return; global.resume_saver = gtk_timeout_add(20000, resume_save, NULL); } void resume_saver_stop() { if (global.resume_saver >= 0) { gtk_timeout_remove(global.resume_saver); global.resume_saver = -1; } } void resume_draw_segments(GtkWidget* win, GdkWindow* window, resume_t* resume, file_segment_t** selected) { int height; int width; static GdkGC *gc = NULL; GdkColor background = { 0, 0xbf00, 0xbf00, 0xbf00 }; style_t *style1; style_t *style2; file_segment_t** segment; double percent1; double percent2; int w1, w2, i1; GtkCList* clist; long size; file_segment_t* seg; GList* dlist; style1 = style_get(global.scheme, "transfer_bar1"); style2 = style_get(global.scheme, "transfer_bar2"); if (!style1 || !style2) return; if (!window) { printf("no window\n"); return; } if (resume->comp_size == 0) { dlist = resume->parts; if (dlist) { while (dlist->next) dlist = dlist->next; seg = dlist->data; size = seg->start+seg->size; } else size = 1000; } else { size = resume->comp_size; } if (!gdk_color_alloc (gtk_widget_get_colormap(GTK_WIDGET(win)), &background) || !gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(win)), style1->fore) || !gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(win)), style1->back) || !gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(win)), style2->fore) || !gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(win)), style2->back)) { g_error("couldn't allocate colour"); } gdk_window_get_size(window, &width, &height); if (!gc) gc = gdk_gc_new(window); gdk_draw_rectangle(window, win->style->bg_gc[0], TRUE, 0, 0, width, height); height -= 6; // draw border gdk_gc_copy(gc, GTK_WIDGET(win)->style->black_gc); gdk_draw_rectangle(window, gc, TRUE, 0, 0, width, height); // draw the background (unfilled progress) gdk_gc_set_foreground(gc, &background); gdk_draw_rectangle(window, gc, TRUE, 1, 1, width - 2, height - 2); // draw the actual progress bar // draw the lower/right white lines clist = GTK_CLIST(lookup_widget(win, "clist37")); i1 = 0; gdk_gc_copy(gc, GTK_WIDGET(win)->style->white_gc); while (1) { if (i1 >= clist->rows) break; segment = gtk_clist_get_row_data(clist, i1); if (segment == selected) gdk_gc_set_foreground(gc, style2->back); else gdk_gc_set_foreground(gc, style1->back); percent1 = (double)segment[0]->start/(double)size; percent2 = (double)(segment[0]->start+segment[0]->size)/(double)size; w1 = (int) ((width - 2) * percent1); w2 = (int) ((width - 2) * percent2); if (w2 - w1 > 0) gdk_draw_rectangle(window, gc, TRUE, w1+1, 1, w2-w1, height/2 - 1); if (segment[0]->flags & PART_CHECK_ERROR) { gdk_draw_line(window, GTK_WIDGET(win)->style->black_gc, w2, height, w2, height+5); gdk_draw_line(window, GTK_WIDGET(win)->style->black_gc, w2, height+5, w2-5, height+5); gdk_draw_line(window, GTK_WIDGET(win)->style->black_gc, w2-5, height+5, w2, height); } percent1 = (double)segment[1]->start/(double)size; percent2 = (double)(segment[1]->start+segment[1]->size)/(double)size; w1 = (int) ((width - 2) * percent1); w2 = (int) ((width - 2) * percent2); if (w2 - w1 > 0) gdk_draw_rectangle(window, gc, TRUE, w1+1, 1, w2-w1, height - 2); i1++; } return; } void seg_list_destroy(gpointer data) { file_segment_t** segment = data; file_segment_destroy(segment[1]); g_free(segment); } void resume_options_setup(GtkWidget* win, resume_t* resume) { GtkCList* clist; GList* dlist; file_segment_t* segment; int row; file_segment_t** seg_list; clist = GTK_CLIST(lookup_widget(win, "clist37")); gtk_clist_clear(clist); for (dlist = resume->parts; dlist; dlist = dlist->next) { segment = dlist->data; // only add segments with sufficient size if (segment->size < 1000) continue; sprintf(tstr[0], "%d - %d", segment->start, segment->start+segment->size); row = gtk_clist_append(clist, list); seg_list = g_malloc(2*sizeof(*seg_list)); seg_list[0] = segment; seg_list[1] = file_segment_new(segment->start, segment->stop); seg_list[1]->size = segment->size; gtk_clist_set_row_data_full(clist, row, seg_list, seg_list_destroy); } } void resume_draw_segment(GtkWidget* win, GdkWindow* window, file_segment_t** segment) { int height; int width; static GdkGC *gc = NULL; style_t *style1; GdkFont *font; GdkColor background = { 0, 0xbf00, 0xbf00, 0xbf00 }; long w1, w2; double percent1, percent2; GtkWidget* temp; style1 = style_get(global.scheme, "transfer_bar2"); if (!style1) return; if (!window) { printf("no window\n"); return; } if (!gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(win)), &background) || !gdk_color_alloc(gtk_widget_get_colormap(GTK_WIDGET(win)), style1->back)) { g_error("couldn't allocate colour"); } font = gdk_fontset_load ("-Adobe-Helvetica-medium-R-Normal--*-100-*-*-*-*-iso8859-*,*-medium-R-Normal--*-100-*"); gdk_window_get_size(window, &width, &height); if (!gc) gc = gdk_gc_new(window); gdk_draw_rectangle(window, win->style->bg_gc[0], TRUE, 0, 0, width, height); // draw border gdk_gc_copy(gc, GTK_WIDGET(win)->style->black_gc); gdk_draw_rectangle(window, gc, TRUE, 5, 20, width-10, height-30); // draw the background (unfilled progress) gdk_gc_set_foreground(gc, &background); gdk_draw_rectangle(window, gc, TRUE, 6, 21, width-12, height-32); percent1 = (double)(segment[1]->start-segment[0]->start)/ (double)segment[0]->size; w1 = (int) ((width - 12) * percent1); percent2 = (double)(segment[1]->start-segment[0]->start+segment[1]->size)/(double)segment[0]->size; w2 = (int) ((width - 12) * percent2); if (!segment[0]->socket && w2 > 0) { gdk_gc_set_foreground(gc, style1->back); gdk_draw_rectangle(window, gc, TRUE, 6+w1, 21, w2-w1, height-32); } gdk_gc_copy(gc, GTK_WIDGET(win)->style->black_gc); if (segment[0]->socket) { strcpy(tstr[0], "Not editable: Segment is in use!"); gdk_draw_string(window, font, gc, (width-7-gdk_string_width(font, tstr[0]))/2, 15, tstr[0]); } else if (segment[0]->flags & PART_CHECK_ERROR) { strcpy(tstr[0], "Not merge-able with next segment!"); gdk_draw_string(window, font, gc, (width-7-gdk_string_width(font, tstr[0]))/2, 15, tstr[0]); } else { strcpy(tstr[0], "Left- or right-click the bar to edit"); gdk_draw_string(window, font, gc, (width-7-gdk_string_width(font, tstr[0]))/2, 15, tstr[0]); } sprintf(tstr[0], "Merge counter: %d", segment[0]->merge_cnt); gdk_draw_string(window, font, gc, (width-7-gdk_string_width(font, tstr[0]))/2, (height+10+gdk_string_height(font, tstr[0]))/2, tstr[0]); gdk_gc_copy(gc, GTK_WIDGET(win)->style->black_gc); gdk_draw_line(window, gc, w1-1, height-3, 5+w1, height-9); gdk_draw_line(window, gc, 5+w1, height-9, 5+w1, height-3); gdk_draw_line(window, gc, 5+w1, height-3, w1-1, height-3); gdk_draw_line(window, gc, 6+w2, height-9, 6+w2, height-3); gdk_draw_line(window, gc, 6+w2, height-3, 12+w2, height-3); gdk_draw_line(window, gc, 12+w2, height-3, 6+w2, height-9); gdk_draw_line(window, gc, 5, 3, 5, 17); gdk_draw_line(window, gc, width-6, 3, width-6, 17); sprintf(tstr[0], "%d", segment[0]->start); gdk_draw_string(window, font, gc, 8, 15, tstr[0]); sprintf(tstr[0], "%d", segment[0]->start+segment[0]->size); gdk_draw_string(window, font, gc, width-7-gdk_string_width(font, tstr[0]), 15, tstr[0]); temp = lookup_widget(win, "label1706"); print_size(tstr[0], segment[1]->start-segment[0]->start); gtk_label_set_text(GTK_LABEL(temp), tstr[0]); temp = lookup_widget(win, "label1707"); print_size(tstr[0], segment[1]->size); gtk_label_set_text(GTK_LABEL(temp), tstr[0]); temp = lookup_widget(win, "label1708"); print_size(tstr[0], segment[0]->start+segment[0]->size-segment[1]->start-segment[1]->size); gtk_label_set_text(GTK_LABEL(temp), tstr[0]); return; } void change_segment(GtkWidget* win, file_segment_t** segment) { resume_t *resume; GtkWidget* temp; if (!segment) return; temp = lookup_widget(win, "drawingarea14"); gtk_object_set_data(GTK_OBJECT(temp), "segment", segment); resume_draw_segment(win, temp->window, segment); temp = lookup_widget(win, "drawingarea13"); gtk_object_set_data(GTK_OBJECT(temp), "segment", segment); resume = gtk_object_get_data(GTK_OBJECT(win), "resume"); resume_draw_segments(win, temp->window, resume, segment); temp = lookup_widget(win, "entry134"); print_bytes(tstr[0], segment[1]->start); gtk_entry_set_text(GTK_ENTRY(temp), tstr[0]); temp = lookup_widget(win, "entry135"); print_bytes(tstr[0], segment[1]->start+segment[1]->size); gtk_entry_set_text(GTK_ENTRY(temp), tstr[0]); return; } void resume_modify_values(GtkWidget* win) { file_segment_t** segment; GtkWidget* temp; char* text; long start, stop; temp = lookup_widget(win, "drawingarea13"); segment = gtk_object_get_data(GTK_OBJECT(temp), "segment"); if (!segment || segment[0]->socket) return; temp = lookup_widget(win, "entry134"); text = gtk_entry_get_text(GTK_ENTRY(temp)); start = extract_bytes(text); temp = lookup_widget(win, "entry135"); text = gtk_entry_get_text(GTK_ENTRY(temp)); stop = extract_bytes(text); start = CLAMP(start, segment[0]->start, segment[0]->start+segment[0]->size); stop = CLAMP(stop, start, segment[0]->start+segment[0]->size); segment[1]->start = start; segment[1]->stop = stop; segment[1]->size = stop-start; change_segment(win, segment); } int resume_finished(resume_t* resume) { file_segment_t* segment; if (g_list_length(resume->parts) != 1) return 0; segment = resume->parts->data; if (segment->start == 0 && segment->size == resume->comp_size) return 1; else return 0; } static void dead_destroy(dead_t* dead) { if (dead->fd >= 0) close(dead->fd); g_free(dead->filename); g_list_foreach(dead->segments, (GFunc)g_free, NULL); g_list_free(dead->segments); g_free(dead); } static void scan_end(gboolean close_win) { if (!ScanWin) return; if (ScanIdle >= 0) { gtk_idle_remove(ScanIdle); ScanIdle = -1; } if (close_win) { GList* dlist; gtk_widget_destroy(ScanWin); ScanWin = NULL; for (dlist = DeadFiles; dlist; dlist = dlist->next) { dead_t* dead = dlist->data; dead_destroy(dead); } g_list_free(DeadFiles); DeadFiles = NULL; } } static void on_scan_destroy() { scan_end(TRUE); } static gboolean on_scan_delete() { scan_end(TRUE); return TRUE; } static gint scan_files(); static void on_scan_start(GtkWidget* button) { gtk_widget_set_sensitive(button, FALSE); ScanIdle = gtk_idle_add(scan_files, NULL); } static void on_scan_abort() { scan_end(TRUE); } #define MIN_ZERO_SIZE 1024*4 #define PRE_LOAD 2 static long check_data(dead_t* dead, long pos) { long i1; int res; static char buffer[MIN_ZERO_SIZE]; if (lseek(dead->fd, pos, SEEK_SET) == (off_t)-1) return -1; res = read(dead->fd, buffer, PRE_LOAD); if (res < 0) return -2; if (res == 0) return -3; for (i1 = 0; i1 < PRE_LOAD; i1++) { if (buffer[i1] != 0) return pos+i1; } res = read(dead->fd, buffer+PRE_LOAD, MIN_ZERO_SIZE-PRE_LOAD); if (res < 0) return -2; if (res == 0) return -3; for (i1 = PRE_LOAD; i1 < res+PRE_LOAD; i1++) if (buffer[i1] != 0) return (pos+i1>100)?pos+i1:0; return -4; } static gint file_scan_idle(dead_t* dead) { GList* dlist; int cnt = 0; long temp; resume_t* newfile; double per; for (cnt = 0; cnt < 10; cnt++) { temp = check_data(dead, dead->current_pos); switch (temp) { case -1: // lseek error, should be EOF case -3: // read 0 bytes, should be EOF if (dead->start_found >= 0) { file_segment_t* segment; segment = file_segment_new(dead->start_found, dead->current_pos - MIN_ZERO_SIZE); segment->size = segment->stop - segment->start; dead->start_found = -1; #ifdef RESUME_DEBUG printf(" - new segment from %d to %d\n", segment->start, segment->stop); #endif dead->segments = g_list_append(dead->segments, segment); } gtk_label_set_text(dead->action, "Finished"); gtk_toggle_button_set_active(dead->check, FALSE); gtk_widget_set_sensitive(GTK_WIDGET(dead->box), FALSE); gtk_progress_bar_update(dead->progress, 1.0); // now create resume and attach segments newfile = resume_new(global.current_time); newfile->filename = dead->filename; dead->filename = NULL; for (dlist = dead->segments; dlist; dlist = dlist->next) { file_segment_t* t = dlist->data; newfile->inc_size += t->stop - t->start; } newfile->parts = dead->segments; dead->segments = NULL; resume_show(newfile); resume_save(NULL); DeadFiles = g_list_remove(DeadFiles, dead); dead_destroy(dead); gtk_idle_remove(ScanIdle); ScanIdle = gtk_idle_add(scan_files, NULL); return 0; case -2: // read error gtk_label_set_text(dead->action, "Read error"); gtk_toggle_button_set_active(dead->check, FALSE); gtk_widget_set_sensitive(GTK_WIDGET(dead->box), FALSE); DeadFiles = g_list_remove(DeadFiles, dead); dead_destroy(dead); gtk_progress_bar_update(dead->progress, 0.0); gtk_idle_remove(ScanIdle); ScanIdle = gtk_idle_add(scan_files, NULL); return 0; case -4: // hole found, so finish segment if there is one if (dead->start_found >= 0 && dead->start_found+MIN_ZERO_SIZE < dead->current_pos) { file_segment_t* segment; segment = file_segment_new(dead->start_found, dead->current_pos - MIN_ZERO_SIZE); segment->size = segment->stop - segment->start; #ifdef RESUME_DEBUG printf(" - new segment from %d to %d\n", segment->start, segment->stop); #endif dead->segments = g_list_append(dead->segments, segment); } dead->start_found = -1; break; default: // >= 0, data found at position if (dead->start_found < 0) dead->start_found = temp; break; } dead->current_pos += MIN_ZERO_SIZE; if (dead->size >= dead->current_pos) { per = (double)dead->current_pos/dead->size; gtk_progress_bar_update(dead->progress, per); } } return 1; } static gint scan_files() { int fd; dead_t* dead; if (!DeadFiles) { scan_end(FALSE); return 0; } #ifdef RESUME_DEBUG printf("still %d files to go\n", g_list_length(DeadFiles)); #endif dead = DeadFiles->data; if (!gtk_toggle_button_get_active(dead->check)) { gtk_label_set_text(dead->action, "Skipped"); gtk_toggle_button_set_active(dead->check, FALSE); gtk_widget_set_sensitive(GTK_WIDGET(dead->box), FALSE); DeadFiles = g_list_remove(DeadFiles, dead); dead_destroy(dead); return 1; } if ((fd = open(dead->filename, O_RDONLY)) < 0) { g_warning("Unable to open() file '%s' (%s) !\n", dead->filename, g_strerror(errno)); DeadFiles = g_list_remove(DeadFiles, dead); dead_destroy(dead); return 1; } gtk_label_set_text(dead->action, "Scanning..."); #ifdef RESUME_DEBUG printf("now scanning [%s]\n", dead->filename); #endif dead->fd = fd; dead->segments = NULL; dead->start_found = -1; dead->current_pos = 0; ScanIdle = gtk_idle_add((GtkFunction)file_scan_idle, dead); return 0; } static void on_scan_unlink() { GList* dlist; dlist = DeadFiles; while (dlist) { dead_t* dead = dlist->data; dlist = dlist->next; if (!gtk_toggle_button_get_active(dead->check)) continue; gtk_widget_destroy(GTK_WIDGET(dead->box)); unlink(dead->filename); dead_destroy(dead); DeadFiles = g_list_remove(DeadFiles, dead); } } static GtkWidget* create_scan_progress_win() { GtkWidget* win; GtkWidget* vbox; GtkWidget* vbox2; GtkWidget* sw; GtkWidget* hbox; GtkWidget* frame; GtkWidget* button; GtkWidget* sep; GtkWidget* label; if (ScanWin) return ScanWin; win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(win), "Scan progress"); gtk_window_set_default_size(GTK_WINDOW(win), 500, 300); ScanWin = win; gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(on_scan_destroy), NULL); gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(on_scan_delete), NULL); vbox = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); gtk_container_add(GTK_CONTAINER(win), vbox); label = gtk_label_new("In the folder for your incomplete files normally should only be the files lopster currently has in its download list. If there are some more files in it, they will be listed below. You either can delete them, or reconstruct to add them to your download list."); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); sw = gtk_scrolled_window_new(NULL, NULL); gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); vbox2 = gtk_vbox_new(FALSE, 5); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), vbox2); gtk_viewport_set_shadow_type (GTK_VIEWPORT(GTK_BIN(sw)->child), GTK_SHADOW_NONE); { struct dirent* dent; DIR* dir; char* name; struct stat st; GtkWidget* vbox3; GtkWidget* check; GtkWidget* bar; long size; dead_t* dead; dir = opendir(global.incomplete_path); while (dir && (dent = readdir(dir)) != NULL) { if (dent->d_name[0] == '.') continue; #ifdef RESUME_DEBUG printf("found file [%s]\n", dent->d_name); #endif if (resume_search_short_file(dent->d_name)) { #ifdef RESUME_DEBUG printf(" - is in incomplete.list\n"); #endif continue; } name = g_strdup_printf("%s%c%s", global.incomplete_path, DIR_SEP, dent->d_name); if (stat(name, &st) < 0) size = 0; else size = st.st_size; dead = g_malloc0(sizeof(*dead)); dead->filename = name; dead->size = size; dead->fd = -1; dead->start_found = -1; vbox3 = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox2), vbox3, FALSE, FALSE, 0); dead->box = GTK_BOX(vbox3); check = gtk_check_button_new_with_label(dent->d_name); gtk_box_pack_start(dead->box, check, FALSE, FALSE, 0); dead->check = GTK_TOGGLE_BUTTON(check); // if (dead->size >= 1024) // gtk_toggle_button_set_active(dead->check, TRUE); hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(dead->box, hbox, FALSE, FALSE, 0); label = gtk_label_new("Waiting"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); dead->action = GTK_LABEL(label); bar = gtk_progress_bar_new(); gtk_box_pack_end(GTK_BOX(hbox), bar, FALSE, FALSE, 0); dead->progress = GTK_PROGRESS_BAR(bar); name = g_strdup_printf("Size: %ld (%s)", dead->size, print_size(tstr[0], dead->size)); label = gtk_label_new(name); g_free(name); gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0); DeadFiles = g_list_append(DeadFiles, dead); } closedir(dir); } if (!DeadFiles) { label = gtk_label_new("No dead files found"); gtk_box_pack_start(GTK_BOX(vbox2), label, FALSE, FALSE, 0); } sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); frame = gtk_frame_new(NULL); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); hbox = gtk_hbox_new(TRUE, 5); gtk_container_add(GTK_CONTAINER(frame), hbox); gtk_container_set_border_width(GTK_CONTAINER(hbox), 3); button = gtk_button_new_with_label("Reconstruct selected"); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(on_scan_start), NULL); button = gtk_button_new_with_label("Delete selected"); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(on_scan_unlink), NULL); button = gtk_button_new_with_label("Abort"); gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(on_scan_abort), NULL); gtk_widget_show_all(win); return win; } void resume_scan_dead() { create_scan_progress_win(); // ScanIdle = gtk_idle_add(scan_files, NULL); } void resume_set_size(resume_t* resume, long size) { GList* dlist; socket_t* socket; download_t* download; GList* to_remove = NULL; if (size == 0) return; resume->comp_size = size; if (resume->search) { resume->search->pattern->size_lo = resume->search->pattern->size_hi = size; } for (dlist = resume->downloads; dlist; dlist = dlist->next) { socket = dlist->data; download = socket->data; if (download->file->size != size) to_remove = g_list_append(to_remove, socket); } for (dlist = to_remove; dlist; dlist = dlist->next) { socket = dlist->data; socket_destroy(socket, S_CANCELED); } g_list_free(to_remove); resume_save(NULL); } void segment_size_show(GtkWidget* area, int new_size) { int posx; int posy; char str[1024]; char str2[1024]; int width, height; GtkStyle* style; if (!area->window) return; width = area->allocation.width; height = area->allocation.height; style = area->style; gdk_draw_rectangle(area->window, style->bg_gc[0], TRUE, 0, 0, width, height); posx = (width - 3) * (new_size-1) / 19; if (posx > width-3) posx = width-3; if (posx > 0) gdk_draw_rectangle(area->window, style->bg_gc[3], TRUE, 1, 1, posx, height-3); global.limit.min_segment_size = (1<style->font, str2))/2; posx = gdk_string_width(style->font, "A"); posy = (height + style->font->ascent)/2 - 1; gdk_draw_text (area->window, style->font, style->fg_gc[3], posx, posy, str2, strlen (str2)); }