/* 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 "support.h" #include "interface.h" #include "lopster.h" #include "global.h" #include "search.h" #include "share2.h" #include "mp3_ext.h" #include "ogg_ext.h" #include "flac_ext.h" #include "md5.h" #include "scheme.h" #include "callbacks.h" #include "handler.h" #include "connection.h" #include "preferences.h" #include "dialog.h" #include "dirselect.h" #include "clist_rename.h" #include "file_tree.h" #include "utils.h" #include "files.h" #include "mtypes.h" static int lib_version = 0; static int stype = 0; static file_node_t* snode; static const char ltable[3][3] = { { LIB_SHARED_NONE, LIB_SHARED_PART, LIB_SHARED_PART }, { LIB_SHARED_PART, LIB_SHARED_PART, LIB_SHARED_PART }, { LIB_SHARED_PART, LIB_SHARED_PART, LIB_SHARED_ALL } }; static void file_parse_header(file_t * file) { char *suf; suf = strrchr(file->longname, '.'); if (suf) suf++; if (!suf) { file->bitrate = 32; file->frequency = 32000; file->duration = 60; } else if (!g_strcasecmp(suf, "MP3")) { file_parse_mp3_header(file); #ifdef HAVE_OGG } else if (!g_strcasecmp(suf, "OGG")) { file_parse_ogg_header(file); #endif #ifdef HAVE_FLAC } else if (!g_strcasecmp(suf, "FLAC")) { file_parse_flac_header(file); #endif } else { file->bitrate = 24; file->frequency = 16000; file->duration = 600; } } static void file_calc_md5(file_t * file) { int i1; char str[33]; char hex[16] = "0123456789abcdef"; if (file->md5) g_free(file->md5); file->md5 = NULL; if (global.options.dummy_md5) { for (i1 = 0; i1 < 32; i1++) str[i1] = hex[random() % 16]; str[32] = 0; file->md5 = g_strdup_printf("%s-%ld", str, file->size); } else { file->md5 = MD5File(file->longname, file->md5); } } static void lib_node_update_size(lib_node_t* node) { struct stat stats; file_t* file; file = FILE_NODE(node)->file; if (!file) return; if (stat(file->longname, &stats) < 0) return; node->mod_time = stats.st_mtime; if (file->size != stats.st_size) { file->size = stats.st_size; file_parse_header(file); file_calc_md5(file); } return; } static time_t file_update_size(file_t* file) { struct stat stats; if (!file) return 0; if (stat(file->longname, &stats) < 0) return 0; if (file->size != stats.st_size) { file->size = stats.st_size; file_parse_header(file); file_calc_md5(file); } return stats.st_mtime; } /////////////////////////////////////////////////////// static dir_position_t* dir_position_new(library_t* lib, char* base, int type) { dir_position_t* pos; DIR* dir; dir_pos_entry_t* entry; char* base_folder; if (!base) return NULL; pos = g_malloc(sizeof(dir_position_t)); if (!pos) return NULL; pos->lib = lib; if (base[strlen(base)-1] == DIR_SEP) base_folder = g_strdup(base); else base_folder = g_strdup_printf("%s%c", base, DIR_SEP); dir = opendir(base_folder); if (!dir) { g_free(base_folder); g_free(pos); return NULL; } pos->type = type; pos->base = g_strdup(base_folder); entry = g_malloc(sizeof(dir_pos_entry_t)); entry->dir = dir; entry->folder = base_folder; entry->dent = NULL; pos->stack = g_list_prepend(NULL, entry); return pos; } static void dir_position_destroy(dir_position_t* pos) { if (!pos) return; // FIXME: close left open DIRs, free entries if (pos->stack) g_list_free(pos->stack); if (pos->base) g_free(pos->base); g_free(pos); } static int dir_position_next(dir_position_t* pos) { dir_pos_entry_t* entry; struct dirent* dent; struct stat buf; dir_pos_entry_t* n_entry; char* name; DIR* dir; if (!pos) return 0; while (1) { entry = pos->stack->data; dent = readdir(entry->dir); if (!dent) { if (entry->dir) closedir(entry->dir); g_free(entry->folder); g_free(entry); pos->stack = g_list_remove_link(pos->stack, pos->stack); } else { if (dent->d_name[0] == '.') continue; name = g_strdup_printf("%s%s", entry->folder, dent->d_name); stat(name, &buf); if (buf.st_mode & S_IFDIR) { dir = opendir(name); if (dir) { n_entry = g_malloc(sizeof(dir_pos_entry_t)); n_entry->folder = g_strdup_printf("%s/", name); g_free(name); n_entry->dir = dir; n_entry->dent = NULL; pos->stack = g_list_prepend(pos->stack, n_entry); break; } else g_free(name); } else { // printf("is no dir\n"); entry->dent = dent; g_free(name); break; } } if (!pos->stack) return 0; } return 1; } static char* dir_position_get_current_name(dir_position_t* pos, char** file) { GList* dlist; dir_pos_entry_t* entry; dlist = pos->stack; if (!dlist) return NULL; entry = dlist->data; if (entry->dent) (*file) = entry->dent->d_name; else (*file) = NULL; return entry->folder; } //////////////////////////////////////////////////// static void file_unshare(file_node_t* node, net_t* net) { // dont unshare offline files on server (they are not shared) if (node->flags & LIB_VIRTUAL) return; command_send_unimportant (net, CMD_REMOVE_FILE, node->file->winname); LIB_NODE(node)->nets = g_list_remove(LIB_NODE(node)->nets, net); } static void file_share(file_node_t* node, net_t* net) { file_t* file = node->file; // dont share offline files on server (but they are shown on direct browse) if (node->flags & LIB_VIRTUAL) return; if (!net) { printf("*** file_share error\n"); return; } if (file->media_type == MEDIA_MP3 || global.options.share_as_mp3) { command_send_unimportant (net, CMD_ADD_FILE, file->winname, file->md5, file->size, find_valid_bitrate(file->bitrate), file->frequency, file->duration); } else { command_send_unimportant (net, CMD_SHARE_FILE, file->winname, file->size, file->md5, int2media((file->media_type == MEDIA_NONE) ? (MEDIA_APPLICATION):(file->media_type), 2)); } LIB_NODE(node)->nets = g_list_append(LIB_NODE(node)->nets, net); } static void lib_node_unshared(file_node_t* node) { file_tree_t* tree = FILE_TREE(global.lib); file_node_t* parent; if (!tree || !node || !node->file) return; parent = node; while (parent) { parent->fci[node->file->media_type][0]++; parent->fci[node->file->media_type][1]--; parent->fsi[node->file->media_type][0] += node->file->size; parent->fsi[node->file->media_type][1] -= node->file->size; parent->fci[MEDIA_SIZE][0]++; parent->fci[MEDIA_SIZE][1]--; if (parent->fci[MEDIA_SIZE][1] == 0) parent->flags &= ~LIB_SHARED; parent->fsi[MEDIA_SIZE][0] += node->file->size; parent->fsi[MEDIA_SIZE][1] -= node->file->size; parent = parent->parent; } tree->fci[node->file->media_type][0]++; tree->fci[node->file->media_type][1]--; tree->fsi[node->file->media_type][0] += node->file->size; tree->fsi[node->file->media_type][1] -= node->file->size; tree->fci[MEDIA_SIZE][0]++; tree->fci[MEDIA_SIZE][1]--; tree->fsi[MEDIA_SIZE][0] += node->file->size; tree->fsi[MEDIA_SIZE][1] -= node->file->size; } static void lib_node_unshare(file_node_t* node) { GList* dlist; net_t* net; file_node_t* child; if (!node) return; if (node->file) { if (!(node->flags & LIB_OLD)) return; dlist = LIB_NODE(node)->nets; while (dlist) { net = dlist->data; dlist = dlist->next; file_unshare(node, net); } node->flags &= ~LIB_SHARED; node->flags &= ~LIB_OLD; lib_node_unshared(node); } else { child = node->child; while (child) { lib_node_unshare(child); child = child->next; } } } static void lib_node_removed(file_node_t* node) { file_tree_t* tree = FILE_TREE(global.lib); file_node_t* parent; if (!tree || !node || !node->file) return; parent = node; while (parent) { parent->fci[node->file->media_type][0]--; parent->fci[node->file->media_type][3]--; parent->fsi[node->file->media_type][0] -= node->file->size; parent->fsi[node->file->media_type][3] -= node->file->size; parent->fci[MEDIA_SIZE][0]--; parent->fci[MEDIA_SIZE][3]--; parent->fsi[MEDIA_SIZE][0] -= node->file->size; parent->fsi[MEDIA_SIZE][3] -= node->file->size; parent = parent->parent; } tree->fci[node->file->media_type][0]--; tree->fci[node->file->media_type][3]--; tree->fsi[node->file->media_type][0] -= node->file->size; tree->fsi[node->file->media_type][3] -= node->file->size; tree->fci[MEDIA_SIZE][0]--; tree->fci[MEDIA_SIZE][3]--; tree->fsi[MEDIA_SIZE][0] -= node->file->size; tree->fsi[MEDIA_SIZE][3] -= node->file->size; } static void lib_node_shared(file_node_t* node) { file_tree_t* tree = FILE_TREE(global.lib); file_node_t* parent; if (!tree || !node || !node->file) return; parent = node; while (parent) { parent->fci[node->file->media_type][0]--; parent->fci[node->file->media_type][1]++; parent->fsi[node->file->media_type][0] -= node->file->size; parent->fsi[node->file->media_type][1] += node->file->size; parent->fci[MEDIA_SIZE][0]--; parent->fci[MEDIA_SIZE][1]++; parent->flags |= LIB_SHARED; parent->fsi[MEDIA_SIZE][0] -= node->file->size; parent->fsi[MEDIA_SIZE][1] += node->file->size; parent = parent->parent; } tree->fci[node->file->media_type][0]--; tree->fci[node->file->media_type][1]++; tree->fsi[node->file->media_type][0] -= node->file->size; tree->fsi[node->file->media_type][1] += node->file->size; tree->fci[MEDIA_SIZE][0]--; tree->fci[MEDIA_SIZE][1]++; tree->fsi[MEDIA_SIZE][0] -= node->file->size; tree->fsi[MEDIA_SIZE][1] += node->file->size; } static void lib_node_share(file_node_t* node) { GList* dlist; net_t* net; file_node_t* child; if (!node) return; if (node->file) { if (!(node->flags & LIB_NEW)) return; for (dlist = global.net_active; dlist; dlist = dlist->next) { net = dlist->data; if (!net->active_server || net->active_server->status != SERVER_ONLINE || (net->flags & NETWORK_DONT_SHARE)) continue; file_share(node, net); } node->flags |= LIB_SHARED; node->flags &= ~LIB_NEW; lib_node_shared(node); } else { child = node->child; while (child) { lib_node_share(child); child = child->next; } } } static void lib_update_rec(file_tree_t* tree, file_node_t* node) { file_node_t* node2; while (node) { node2 = node->next; if (node->file) { if (node->flags & LIB_REMOVE) { // not in lib anymore if (node->flags & LIB_SHARED) { node->flags |= LIB_OLD; lib_node_unshare(node); } lib_node_removed(node); file_tree_node_remove(tree, node); file_node_destroy(tree, node); } else if (node->flags & LIB_NEW) { // new file lib_node_share(node); } } else { if (node->child) { // folder lib_update_rec(tree, node->child); } if (!node->child) { file_tree_node_remove(tree, node); file_node_destroy(tree, node); } } node = node2; } } static void lib_update(library_t* lib) { file_tree_t* tree = FILE_TREE(lib); if (!tree || !tree->files) return; lib_update_rec(tree, tree->files); } static file_node_t* share_cb(file_node_t* node, void* data) { net_t* net = data; if (node->file && (node->flags & LIB_SHARED)) { file_share(node, net); } return NULL; } void lib_share(library_t* lib, net_t* net) { if (!net) { GList* dlist; for (dlist = global.net_active; dlist; dlist = dlist->next) { net = dlist->data; if (net->flags & NETWORK_DONT_SHARE) continue; file_node_action(FILE_TREE(lib), NULL, share_cb, net); } } else { if (net->flags & NETWORK_DONT_SHARE) return; file_node_action(FILE_TREE(lib), NULL, share_cb, net); } } static void lib_finish(library_t* lib) { file_tree_t* tree = FILE_TREE(lib); if (!tree) return; lib->status = -1; tree->last_refreshed = global.current_time; gtk_progress_set_percentage(GTK_PROGRESS (tree->progress), 0.0); gtk_progress_set_activity_mode (GTK_PROGRESS (tree->progress), FALSE); lib_update(lib); file_tree_calc_matrix(tree); file_tree_show(tree, tree->show_mime, tree->show_time); file_tree_mark(tree, 0); lib_save(lib, tree->name); } static void lib_update_user(file_tree_t* tree) { GtkProgress* bar; static float pos = 0.0; if (!tree->progress) return; bar = GTK_PROGRESS(tree->progress); pos += 0.0001; if (pos > 0.99) pos = 0.0; gtk_progress_set_percentage(bar, pos); } static gint dir_for_all_idle(gpointer data) { dir_position_t* pos = data; char* name; file_node_t* node; file_tree_t* tree = FILE_TREE(pos->lib); char* filename; char* folder; file_t* file; folder = dir_position_get_current_name(pos, &filename); if (filename && (pos->type == MEDIA_NONE || mtype_contains_suffix(pos->type, filename))) { name = g_strdup_printf("%s%s", folder, filename); node = file_tree_search_filename(tree, name); if (!node) { file = file_create_from_local(name); node = file_tree_insert_file(tree, file); } else { lib_update_user(tree); node->flags &= ~LIB_REMOVE; } g_free(name); lib_node_update_size(LIB_NODE(node)); } if (!dir_position_next(pos)) { pos->lib->status--; if (pos->lib->status == 0) lib_finish(pos->lib); dir_position_destroy(pos); return 0; } return 1; } static gint dir_for_all_idle2(gpointer data) { dir_position_t* pos = data; char* name; file_node_t* node; file_tree_t* tree = FILE_TREE(pos->lib); char* filename; char* folder; time_t mod; file_t* file; int len; folder = dir_position_get_current_name(pos, &filename); if (filename && (pos->type == MEDIA_NONE || mtype_contains_suffix(pos->type, filename))) { name = g_strdup_printf("%s%s", folder, filename); file = file_create_from_local(name); g_free(name); mod = file_update_size(file); // changing filename g_free(file->longname); g_free(file->winname); len = strlen("[OFFLINE] ") + strlen(filename); if (snode->name[strlen(snode->name)-1] != DIR_SEP) { char* str = g_strdup_printf("%s%c", snode->name, DIR_SEP); g_free(snode->name); snode->name = str; } file->longname = file_node_get_folder(snode, &len); sprintf(file->longname+len, "[OFFLINE] %s", filename); file->winname = g_strdup(file->longname); file->shortname = get_short_name(file->longname); file->filename = get_file_name(file->shortname); local_to_napster_hide(file->winname); node = file_tree_insert_file(tree, file); LIB_NODE(node)->mod_time = mod; node->flags |= LIB_VIRTUAL; } if (!dir_position_next(pos)) { pos->lib->status--; if (pos->lib->status == 0) lib_finish(pos->lib); dir_position_destroy(pos); return 0; } return 1; } /////////////////////////////////// static file_node_t* lib_node_new(char* name) { lib_node_t* node; if (!name) return NULL; node = g_malloc(sizeof(lib_node_t)); if (!node) return NULL; file_node_init(FILE_NODE(node), name); node->mod_time = 0; node->nets = NULL; return FILE_NODE(node); } static void lib_node_free(file_node_t* node) { if (!node) return; if (node->file && (node->flags & LIB_DELETE)) { unlink(node->file->longname); } } static int lib_node_rename_func(clist_rename_t* cr) { int row; file_node_t* node; char* new_name; char* pos; int res; int old_shared; struct stat stats; if (!cr || !cr->new_text || !cr->data) return 0; row = gtk_clist_find_row_from_data(cr->clist, cr->data); if (row < 0) return 0; node = cr->data; if (!node->file) return 0; if (strchr(cr->new_text, DIR_SEP)) return 0; pos = strrchr(node->file->longname, DIR_SEP); if (pos) { *pos = 0; new_name = g_strdup_printf("%s%c%s", node->file->longname, DIR_SEP, cr->new_text); *pos = DIR_SEP; } else { new_name = g_strdup(cr->new_text); } if (stat(new_name, &stats) == 0) { g_free(new_name); info_dialog("Cannot rename file, filename already in use!"); return 0; } if ((res = rename(node->file->longname, new_name)) != 0) { char* str; str = g_strdup_printf("Renaming from\n [%s]\nto\n [%s]\nfailed (%s)\n", node->file->longname, new_name, strerror(errno)); info_dialog(str); g_free(new_name); g_free(str); return 0; } // unshare on all servers old_shared = (node->flags & LIB_SHARED); if (old_shared) { node->flags |= LIB_OLD; lib_node_unshare(node); } g_free(node->file->longname); g_free(node->file->winname); node->file->longname = new_name; node->file->shortname = get_short_name(new_name); node->file->filename = get_file_name(new_name); node->file->winname = g_strdup(new_name); local_to_napster_hide(node->file->winname); if (old_shared) { node->flags |= LIB_NEW; lib_node_share(node); } g_free(node->name); node->name = g_strdup(cr->new_text); file_node_update(FILE_TREE(global.lib), node, 0, 0); return 1; } static void lib_node_rename(file_node_t* node) { file_tree_t* tree = FILE_TREE(global.lib); if (!tree || !tree->clist) return; clist_rename(tree->clist, 0, lib_node_rename_func, node, node->name); } ///////////////// static time_t lib_next_mark(file_tree_t* tree, file_node_t* node) { if (LIB_NODE(node)->mod_time + LIB_TREE(tree)->mark > global.current_time) return LIB_TREE(tree)->mark + LIB_NODE(node)->mod_time - global.current_time; else return 0; } static int lib_node_status(file_tree_t* tree, file_node_t* node) { int result = 0; if (!node->file) return 0; if (global.current_time - LIB_TREE(tree)->mark < LIB_NODE(node)->mod_time) result |= (1<<2); // its a new file if (node->flags & LIB_SHARED) result |= (1<<1); // its a shared file else result |= (1<<0); // its unshared return result; } static void lib_save_node(FILE* fd, file_node_t* node, int indent) { file_t* file; while (node) { file = node->file; if (file) { fprintf(fd, "%*s", indent, ""); qfprintf(fd, "FILE %S %s %ld %s%d %d %d %d %lu %d\n", file->filename, file->md5, file->size, file->vbr?"vbr":"", file->bitrate, file->frequency, file->duration, (node->flags & LIB_SHARED)!=0, LIB_NODE(node)->mod_time, (node->flags & LIB_VIRTUAL)!=0); } else if (node->child) { fprintf(fd, "%*s", indent, ""); qfprintf(fd, "DIR %S %d {\n", node->name, (node->flags & LIB_VIRTUAL)!=0); lib_save_node(fd, node->child, indent+2); fprintf(fd, "%*s}\n", indent, ""); } node = node->next; } } static void lib_node_init(file_node_t* node) { file_tree_t* tree = FILE_TREE(global.lib); if (!tree) return; // check whether we do a refresh if (global.lib->status == -1) return; // inherit parents share status if (!node->parent || (node->parent->flags & LIB_SHARED)) { if (node->file) node->flags |= LIB_NEW; else node->flags |= LIB_SHARED; } } library_t* lib_new(char* name) { library_t *lib; lib = g_malloc(sizeof(library_t)); if (!lib) return NULL; file_tree_init(FILE_TREE(lib), name, NULL); FILE_TREE(lib)->node_new = lib_node_new; FILE_TREE(lib)->node_status = lib_node_status; FILE_TREE(lib)->update_user = lib_update_user; FILE_TREE(lib)->node_free = lib_node_free; FILE_TREE(lib)->node_init = lib_node_init; FILE_TREE(lib)->next_mark = lib_next_mark; lib->status = -1; lib->mark = 0; lib->shared_folder = NULL; lib->fd = NULL; lib->timeout = -1; return lib; } static GtkWidget* lib_create_page(library_t* lib) { file_tree_t* tree = FILE_TREE(lib); if (tree->ctree)return NULL; if (global.lib) return NULL; global.lib = lib; tree->main_link = lookup_widget(global.win, "hpaned4"); tree->ctree = GTK_CTREE(lookup_widget(global.win, "ctree8")); tree->signal[0] = gtk_signal_connect (GTK_OBJECT (tree->ctree), "tree_select_row", GTK_SIGNAL_FUNC (on_file_tree_select_row), tree); tree->search_entry = lookup_widget(global.win, "entry154"); tree->signal[1] = gtk_signal_connect (GTK_OBJECT (tree->search_entry), "changed", GTK_SIGNAL_FUNC (on_file_tree_search_changed), tree); tree->clist = GTK_CLIST(lookup_widget(global.win, "clist36")); tree->signal[2] = gtk_signal_connect(GTK_OBJECT(tree->clist), "motion_notify_event", GTK_SIGNAL_FUNC(on_tree_motion_notify_event), NULL); tree->signal[3] = gtk_signal_connect(GTK_OBJECT(tree->clist), "leave_notify_event", GTK_SIGNAL_FUNC(on_tree_leave_notify_event), NULL); tree->signal[4] = gtk_signal_connect (GTK_OBJECT (tree->clist), "select_row", GTK_SIGNAL_FUNC (on_file_select_row), tree); tree->resize_cont = lookup_widget(global.win, "hbox162"); tree->button[0] = lookup_widget(global.win, "button362"); tree->blabel[0] = lookup_widget(global.win, "label2691"); tree->signal[5] = gtk_signal_connect (GTK_OBJECT (tree->button[0]), "clicked", GTK_SIGNAL_FUNC (on_file_tree_files1_clicked), tree); tree->button[1] = lookup_widget(global.win, "button363"); tree->blabel[1] = lookup_widget(global.win, "label2692"); tree->signal[6] = gtk_signal_connect (GTK_OBJECT (tree->button[1]), "clicked", GTK_SIGNAL_FUNC (on_file_tree_files2_clicked), tree); tree->label = lookup_widget(global.win, "label2679"); tree->progress = global.progressbar; return GTK_WIDGET(tree->ctree); } void shared_folder_destroy(GList* slist) { GList* dlist; shared_folder_t* folder; if (!slist) return; for (dlist = slist; dlist; dlist = dlist->next) { folder = dlist->data; g_free(folder->name); g_free(folder); } g_list_free(slist); } void lib_destroy(library_t* lib) { file_tree_t* tree = FILE_TREE(lib); if (!lib) return; if (global.lib == lib) { lib_unshare_all(lib); global.lib = NULL; file_tree_release_page(tree); } if (lib->fd) fclose(lib->fd); file_tree_clear_files(tree); shared_folder_destroy(lib->shared_folder); file_tree_destroy(FILE_TREE(lib)); } library_t* lib_create_new(char* name) { library_t* lib; lib = lib_new(name); if (!lib) return NULL; if (global.lib) lib_destroy(global.lib); if (!lib_create_page(lib)) { printf("** lib_create_new(): error ** \n"); } calc_time(global.options.lib_mark_val, &global.lib->mark); return lib; } static file_node_t* set_remove_cb(file_node_t* node, void* flag ATTR_UNUSED) { if (node->file && !(node->flags & LIB_VIRTUAL)) node->flags |= LIB_REMOVE; return NULL; } static void lib_start(library_t* lib) { file_tree_t* tree = FILE_TREE(lib); lib->status = 0; gtk_progress_set_percentage(GTK_PROGRESS (tree->progress), 0.0); gtk_progress_set_activity_mode (GTK_PROGRESS (tree->progress), TRUE); } void lib_refresh(library_t* lib) { file_tree_t* tree = FILE_TREE(lib); GList *dlist = NULL; dir_position_t* pos; shared_folder_t* folder; if (!lib || lib->status >= 0) { if (!lib) g_warning("no lib!"); else g_warning("lib is busy %d", lib->status); return; } file_node_action(tree, NULL, set_remove_cb, NULL); lib_start(lib); for (dlist = lib->shared_folder; dlist; dlist = dlist->next) { folder = dlist->data; pos = dir_position_new(lib, folder->name, folder->type); if (pos) { lib->status++; gtk_idle_add(dir_for_all_idle, pos); } } if (lib->status == 0) lib_finish(lib); return; } void lib_save(library_t* lib, char* name) { char filename[1024]; FILE *fd; GtkWidget* temp; shared_folder_t* sf; GList* dlist; file_tree_t* tree = FILE_TREE(lib); if (!lib) return; if (name && name != tree->name) { g_free(tree->name); tree->name = g_strdup(name); } sprintf(filename, "%s%cshare%c%s", global.options.config_dir, DIR_SEP, DIR_SEP, tree->name); if ((fd = fopen(filename, "w")) == NULL) { g_warning("Could not save shared files %s", filename); return; } qfprintf(fd, "LIBRARY 1 %S %ld %S\n", tree->name, tree->last_refreshed, tree->description?tree->description:""); fprintf(fd, "Section [Folders]\n"); fprintf(fd, "Lines %d\n", g_list_length(lib->shared_folder)); for (dlist = lib->shared_folder; dlist; dlist = dlist->next) { sf = dlist->data; qfprintf(fd, "%S %d\n", sf->name, sf->type); } if (lib == global.lib) { temp = lookup_widget(global.win, "entry84"); gtk_entry_set_text(GTK_ENTRY(temp), tree->name); } fprintf(fd, "Section [Files]\n"); lib_save_node(fd, tree->files, 0); fclose(fd); } static int lib_load_folders(library_t* lib) { char* s1; char* s2; shared_folder_t* folder; int lines; int i1; char line[2048]; if (!lib) return 0; if (!lib->fd) return 0; if (!mfgets(line, sizeof(line), lib->fd)) return 0; s1 = arg(line, 0); s2 = arg(NULL, 0); if (!s2) return 0; if (!strcmp(s1, "LIBRARY")) { lib_version = atoi(s2); if (!mfgets(line, sizeof(line), lib->fd)) return 0; s1 = arg(line, 0); s2 = arg(NULL, 0); if (!s2) return 0; } else { // backward compatible lib_version = 0; } if (strcmp(s1, "Section")) return 0; if (strcmp(s2, "[Folders]")) return 0; if (!mfgets(line, sizeof(line), lib->fd)) return 0; s1 = arg(line, 0); s2 = arg(NULL, 0); if (!s1 || !s2) return 0; if (strcasecmp(s1, "Lines")) return 0; lines = atoi(s2); for (i1 = 0; i1 < lines; i1++) { if (!mfgets(line, sizeof(line), lib->fd)) return 0; s1 = arg(line, 2); s2 = arg(NULL, 2); if (!s1 || !s2) return 0; folder = g_malloc(sizeof(shared_folder_t)); if (!folder) return 0; folder->name = g_strdup(s1); if (!folder->name) return 0; folder->type = atoi(s2); lib->shared_folder = g_list_append(lib->shared_folder, folder); } return 1; } static int lib_load_folder_1(library_t* lib, lib_node_t* parent) { char line[2048]; char *filename; char *md5; char *size; char *bitrate; char *freq; char *duration; char *share; char *modif; char *virt; file_t *file; file_tree_t* tree = FILE_TREE(lib); char* token; lib_node_t* child; int pos; while (mfgets(line, sizeof(line), lib->fd)) { token = arg(line, 0); if (!strcmp(token, "FILE")) { filename = arg(NULL, 2); md5 = arg(NULL, 2); size = arg(NULL, 2); bitrate = arg(NULL, 2); freq = arg(NULL, 2); duration = arg(NULL, 2); share = arg(NULL, 2); modif = arg(NULL, 2); virt = arg(NULL, 2); if (virt) { file = file_new(); pos = strlen(filename); file->longname = file_node_get_folder(FILE_NODE(parent), &pos); strcpy(file->longname+pos, filename); file->shortname = get_short_name(file->longname); file->filename = get_file_name(file->shortname); file->winname = g_strdup(file->longname); local_to_napster_hide(file->winname); file->md5 = g_strdup(md5); file->size = strtoul(size, NULL, 10); if (!strncmp(bitrate, "vbr", 3)) { file->bitrate = atoi(bitrate + 3); file->vbr = 1; } else { file->bitrate = atoi(bitrate); file->vbr = 0; } file->frequency = atoi(freq); file->duration = atoi(duration); file->media_type = mtype_get(file->filename); file->user = g_strdup(""); child = LIB_NODE (file_node_insert_file(tree, FILE_NODE(parent), file, FALSE)); if (atoi(share)) FILE_NODE(child)->flags |= LIB_SHARED; else FILE_NODE(child)->flags &= ~LIB_SHARED; child->mod_time = strtoul(modif, NULL, 10); if (atoi(virt)) FILE_NODE(child)->flags |= LIB_VIRTUAL; else FILE_NODE(child)->flags &= ~LIB_VIRTUAL; } } else if (!strcmp(token, "DIR")) { filename = arg(NULL, 2); virt = arg(NULL, 0); if (filename) { child = LIB_NODE (file_tree_insert_folder(tree, FILE_NODE(parent), filename, 1)); lib_load_folder_1(lib, child); if (virt && atoi(virt)) FILE_NODE(child)->flags |= LIB_VIRTUAL; else FILE_NODE(child)->flags &= ~LIB_VIRTUAL; } } else if (!strcmp(token, "}")) { return 1; } else { // ignore line } } return 1; } static int lib_load_folder_0(library_t* lib) { char *filename; char *md5; char *size; char *bitrate; char *freq; char *duration; char *share; char *modif; char *virt; char line[2048]; file_t *file; file_node_t* child; if (!mfgets(line, sizeof(line), lib->fd)) return 0; filename = arg(line, 2); md5 = arg(NULL, 2); size = arg(NULL, 2); bitrate = arg(NULL, 2); freq = arg(NULL, 2); duration = arg(NULL, 2); share = arg(NULL, 2); modif = arg(NULL, 2); virt = arg(NULL, 2); if (!filename || !md5 || !size || !bitrate || !freq || !duration || !share || !modif || !virt) { return 0; } file = file_new(); file_set_longname(file, filename); file->md5 = g_strdup(md5); file->size = strtoul(size, NULL, 10); if (!strncmp(bitrate, "vbr", 3)) { file->bitrate = atoi(bitrate + 3); file->vbr = 1; } else { file->bitrate = atoi(bitrate); file->vbr = 0; } file->frequency = atoi(freq); file->duration = atoi(duration); file->user = g_strdup(""); child = file_tree_insert_file(FILE_TREE(lib), file); if (atoi(share)) child->flags |= LIB_SHARED; else child->flags &= ~LIB_SHARED; LIB_NODE(child)->mod_time = strtoul(modif, NULL, 10); if (atoi(virt)) { child->flags |= LIB_VIRTUAL; if (child->parent) child->parent->flags |= LIB_VIRTUAL; } else child->flags &= ~LIB_VIRTUAL; return 1; } static int lib_load_files(library_t* lib) { char* s1; char* s2; char line[2048]; if (!lib) return 0; if (!lib->fd) return 0; if (!mfgets(line, sizeof(line), lib->fd)) return 0; s1 = arg(line, 0); s2 = arg(NULL, 0); if (!s2) return 0; if (strcmp(s1, "Section")) return 0; if (strcmp(s2, "[Files]")) return 0; if (lib_version == 0) { while (lib_load_folder_0(lib)) ; } else if (lib_version == 1) { lib_load_folder_1(lib, NULL); } return 1; } static void lib_set_share_flag(library_t* lib) { file_tree_t* tree = FILE_TREE(lib); file_node_t* node; node = tree->files; while (node) { if (!node->file) { if (node->fci[MEDIA_SIZE][1] > 0) node->flags |= LIB_SHARED; else node->flags &= ~LIB_SHARED; } node = file_node_next(node); } } // loading global library library_t* lib_load_saved(char *fname) { GtkWidget* temp; library_t* lib; char filename[2048]; file_tree_t* tree; if (!fname || !(*fname)) return NULL; lib = lib_create_new(fname); if (!lib) return NULL; tree = FILE_TREE(lib); sprintf(filename, "%s%cshare%c%s", global.options.config_dir, DIR_SEP, DIR_SEP, fname); lib->fd = fopen(filename, "r"); if (!lib->fd) { info_dialog("Could not open Library"); lib_destroy(lib); return NULL; } if (!lib_load_folders(lib)) { lib_destroy(lib); info_dialog("Could not load Library (no folder section found)"); return NULL; } if (!lib_load_files(lib)) { lib_destroy(lib); info_dialog("Could not load Library (no file section found)"); return NULL; } if (lib->fd) { fclose(lib->fd); lib->fd = NULL; } gtk_progress_set_percentage(GTK_PROGRESS (tree->progress), 0.0); gtk_progress_set_activity_mode (GTK_PROGRESS (tree->progress), FALSE); file_tree_calc_matrix(tree); lib_set_share_flag(lib); file_tree_show(tree, MEDIA_SIZE, 3); file_tree_mark(tree, 0); temp = lookup_widget(global.win, "entry84"); gtk_entry_set_text(GTK_ENTRY(temp), fname); return lib; } void lib_do_search(search_t* search) { int cnt = 0; if (global.lib) file_tree_search(FILE_TREE(global.lib), search, &cnt); search_finish(search, NULL, 0); } static void lib_delete(char *name) { char filename[1024]; if (!name || !(*name)) return; sprintf(filename, "%s%cshare%c%s", global.options.config_dir, DIR_SEP, DIR_SEP, name); unlink(filename); } static file_node_t* set_unshared_cb(file_node_t* node, void* flag ATTR_UNUSED) { if (LIB_NODE(node)->nets) g_list_free(LIB_NODE(node)->nets); LIB_NODE(node)->nets = NULL; return NULL; } void lib_unshare_all(library_t* lib) { // temp unsharing if (!lib) return; file_node_action(FILE_TREE(lib), NULL, set_unshared_cb, NULL); command_send_unimportant(NULL, CMD_UNSHARE_ALL); } static file_node_t* set_unshared_server_cb(file_node_t* node, void* data) { net_t* net = data; if (node->file) LIB_NODE(node)->nets = g_list_remove(LIB_NODE(node)->nets, net); return NULL; } void lib_unshare_all_network(library_t* lib, net_t* net) { // temp unsharing if (!lib) return; file_node_action(FILE_TREE(lib), NULL, set_unshared_server_cb, net); command_send_unimportant(net, CMD_UNSHARE_ALL); } static GList* get_selected_nodes(GtkCList* clist, int* count, int* count2) { GList* dlist; GList* result = NULL; int row; file_node_t* node; *count = 0; *count2 = 0; for (dlist = clist->selection; dlist; dlist = dlist->next) { row = (int)dlist->data; node = gtk_clist_get_row_data(clist, row); if (node && node->file) { if (node->flags & LIB_SHARED) (*count)++; if (node->flags & LIB_VIRTUAL) (*count2)++; result = g_list_append(result, node); } } return result; } static void on_share_selected_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GList* selected = user_data; file_node_t* node = NULL; GList* dlist; if (!global.lib) return; for (dlist = selected; dlist; dlist = dlist->next) { node = dlist->data; if (!(node->flags & LIB_SHARED)) { node->flags |= LIB_NEW; lib_node_share(node); // update without parents file_node_update(FILE_TREE(global.lib), node, 0, 0); } } // update with parents if (node) file_node_update(FILE_TREE(global.lib), node, 1, 0); lib_save(global.lib, NULL); } static void on_unshare_selected_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GList* selected = user_data; file_node_t* node = NULL; GList* dlist; if (!global.lib) return; for (dlist = selected; dlist; dlist = dlist->next) { node = dlist->data; if (node->flags & LIB_SHARED) { node->flags |= LIB_OLD; lib_node_unshare(node); // update without parents file_node_update(FILE_TREE(global.lib), node, 0, 0); } } // update with parents if (node) file_node_update(FILE_TREE(global.lib), node, 1, 0); lib_save(global.lib, NULL); } static void on_remove_selected_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GList* selected = user_data; file_node_t* node = NULL; file_node_t* parent = NULL; GList* dlist; dlist = selected; while (dlist) { node = dlist->data; parent = node->parent; dlist = dlist->next; if (node->flags & LIB_VIRTUAL) { if (node->flags & LIB_SHARED) { node->flags |= LIB_OLD; lib_node_unshare(node); } lib_node_removed(node); file_tree_node_remove(FILE_TREE(global.lib), node); file_node_destroy(FILE_TREE(global.lib), node); } } node = parent; while (node) { parent = node->parent; if (node->child) break; file_tree_node_remove(FILE_TREE(global.lib), node); file_node_destroy(FILE_TREE(global.lib), node); node = parent; } // update with parents if (node) file_node_update(FILE_TREE(global.lib), node, 1, 0); lib_save(global.lib, NULL); } static void on_button_close_clicked(GtkButton * button, gpointer user_data ATTR_UNUSED) { GtkWidget *temp; temp = lookup_widget(GTK_WIDGET(button), "delete_win"); gtk_widget_hide(temp); gtk_widget_destroy(temp); } static void on_delete_clicked(GtkButton * button, gpointer user_data) { GList* selected = user_data; file_node_t* node = NULL; file_node_t* parent = NULL; GList* dlist; dlist = selected; while (dlist) { node = dlist->data; parent = node->parent; dlist = dlist->next; if (node->flags & LIB_SHARED) { node->flags |= LIB_OLD; lib_node_unshare(node); } node->flags |= LIB_DELETE; lib_node_removed(node); file_tree_node_remove(FILE_TREE(global.lib), node); file_node_destroy(FILE_TREE(global.lib), node); } node = parent; while (node) { parent = node->parent; if (node->child) break; file_tree_node_remove(FILE_TREE(global.lib), node); file_node_destroy(FILE_TREE(global.lib), node); node = parent; } // update with parents if (node) file_node_update(FILE_TREE(global.lib), node, 1, 0); lib_save(global.lib, NULL); on_button_close_clicked(button, NULL); } static void on_del_selected_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GtkWidget *win; GtkWidget *temp; win = create_delete_win(); temp = lookup_widget(win, "button170"); gtk_signal_connect(GTK_OBJECT(temp), "clicked", GTK_SIGNAL_FUNC(on_delete_clicked), user_data); gtk_widget_show(win); } static void on_rename_node_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { lib_node_rename((file_node_t*)user_data); } GtkWidget *create_lib1_popup(file_node_t* node) { file_t* file; GtkWidget *popup; GtkWidget *item; GtkCList *clist; int item_num; static GList* selected = NULL; int shared; int virtual; char* text; popup = gtk_menu_new(); if (node && node->file) { file = node->file; clist = GTK_CLIST(global.popup_list); if (selected) g_list_free(selected); selected = get_selected_nodes(clist, &shared, &virtual); item_num = g_list_length(selected); item = create_open_menu(file->media_type, file->longname, !(node->flags & LIB_VIRTUAL)); 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 (item_num - shared > 0) { if ((item_num > 1) || (item_num - shared > 1)) text = g_strdup_printf("Share Selected (%d)", item_num-shared); else text = g_strdup("Share File"); item = gtk_menu_item_new_with_label(text); g_free(text); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_share_selected_activate), selected); } if (shared > 0) { if ((item_num > 1) || (shared > 1)) text = g_strdup_printf("Unshare Selected (%d)", shared); else text = g_strdup("Unshare File"); item = gtk_menu_item_new_with_label(text); g_free(text); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_unshare_selected_activate), selected); } 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("Rename file"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_rename_node_activate), node); if (node->flags & LIB_VIRTUAL) 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); if (virtual) { if (virtual > 1) text = g_strdup_printf("Remove Files (%d)", virtual); else text = g_strdup("Remove File"); item = gtk_menu_item_new_with_label(text); g_free(text); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_remove_selected_activate), selected); } if (item_num - virtual > 0) { if (item_num - virtual > 1) text = g_strdup_printf("Delete %d files (from disc)", item_num); else text = g_strdup("Delete File (from disc)"); item = gtk_menu_item_new_with_label(text); g_free(text); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_del_selected_activate), selected); } 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; } static file_node_t* share_subtree(file_node_t* node, void* data) { file_tree_t* tree = data; if (node->file && !(node->flags & LIB_SHARED) && node->fci[tree->show_mime][tree->show_time]) { node->flags |= LIB_NEW; } return NULL; } static void on_share_subtree_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { file_node_t* node = user_data; file_node_action(FILE_TREE(global.lib), node, share_subtree, global.lib); lib_node_share(node); // update with parents and childs file_node_update(FILE_TREE(global.lib), node, 1, 1); lib_save(global.lib, NULL); } static file_node_t* unshare_subtree(file_node_t* node, void* data) { file_tree_t* tree = data; if (node->file && (node->flags & LIB_SHARED) && node->fci[tree->show_mime][tree->show_time]) { node->flags |= LIB_OLD; } return NULL; } static void on_unshare_subtree_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { file_node_t* node = user_data; file_node_action(FILE_TREE(global.lib), node, unshare_subtree, global.lib); lib_node_unshare(node); // update with parents and childs file_node_update(FILE_TREE(global.lib), FILE_NODE(node), 1, 1); lib_save(global.lib, NULL); } /* static void on_refresh_subtree_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data ATTR_UNUSED) { printf("on_refresh_subtree not defined\n"); // lib_node_refresh((lib_node_t*)user_data); } */ static int lib_rename_folder_func(clist_rename_t* cr) { GtkCTreeNode* cnode; file_node_t* node; GtkCTree* ctree; if (!cr || !cr->new_text || !cr->data) return 0; ctree = GTK_CTREE(cr->clist); node = cr->data; cnode = gtk_ctree_find_by_row_data(ctree, NULL, node); if (!cnode) return 0; if (node->name) g_free(node->name); node->name = g_strdup(cr->new_text); file_node_update(FILE_TREE(global.lib), node, 0, 0); return 1; } static void on_create_virtual_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { file_node_t* node = user_data; file_node_t* child; if (!global.lib) return; if (!node || node->file) return; /* manually insert new node */ child = file_tree_insert_folder(FILE_TREE(global.lib), node, "[OFFLINE]/", 0); child->flags |= LIB_VIRTUAL; /* now renaming node */ clist_rename(GTK_CLIST(FILE_TREE(global.lib)->ctree), 0, lib_rename_folder_func, child, child->name); } static void on_expand_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GtkCTree* ctree = GTK_CTREE(lookup_widget(global.win, "ctree8")); lib_node_t* node = user_data; GtkCTreeNode* tnode; tnode = gtk_ctree_find_by_row_data(ctree, NULL, node); gtk_ctree_expand_recursive(ctree, tnode); } static void on_collapse_activate(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GtkCTree* ctree = GTK_CTREE(lookup_widget(global.win, "ctree8")); lib_node_t* node = user_data; GtkCTreeNode* tnode; tnode = gtk_ctree_find_by_row_data(ctree, NULL, node); gtk_ctree_collapse_recursive(ctree, tnode); } static void on_offline_dir_select(gchar * dir) { dir_position_t* pos; library_t* lib = global.lib; if (!lib) return; lib_start(lib); pos = dir_position_new(lib, dir, stype); if (pos) { lib->status++; gtk_idle_add(dir_for_all_idle2, pos); } if (lib->status == 0) lib_finish(lib); } static void on_offline_add(GtkMenuItem * menuitem ATTR_UNUSED, gpointer user_data) { GtkWidget *win; stype = (int) user_data; win = create_dir_browser("Select Directory", g_get_home_dir(), GTK_SELECTION_SINGLE, on_offline_dir_select); gtk_widget_show(win); } GtkWidget *create_lib2_popup(lib_node_t* node) { GtkWidget *popup; GtkWidget *item; GtkWidget *popup2; GtkWidget *item2; file_node_t* n2 = FILE_NODE(node); file_tree_t* tree = FILE_TREE(global.lib); char* folder; int temp = 0; if (!node || !tree) return NULL; popup = gtk_menu_new(); folder = file_node_get_folder(FILE_NODE(node), &temp); item = create_open_menu(MEDIA_FOLDER, folder, 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 (tree->fci[MEDIA_SIZE][0] > 0) { item = gtk_menu_item_new_with_label("Share Subtree"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_share_subtree_activate), node); } if (tree->fci[MEDIA_SIZE][1] > 0) { item = gtk_menu_item_new_with_label("Unshare Subtree"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_unshare_subtree_activate), node); } 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("Refresh Subtree (deactivated)"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_refresh_subtree_activate), node); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_widget_set_sensitive(item, FALSE); */ if (n2->flags & LIB_VIRTUAL) { snode = n2; item = gtk_menu_item_new_with_label("Add offline files"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); popup2 = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), popup2); item2 = gtk_menu_item_new_with_label("MP3"); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup2), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_offline_add), (gpointer) MEDIA_MP3); item2 = gtk_menu_item_new_with_label("Video"); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup2), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_offline_add), (gpointer) MEDIA_VIDEO); item2 = gtk_menu_item_new_with_label("Audio"); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup2), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_offline_add), (gpointer) MEDIA_AUDIO); item2 = gtk_menu_item_new_with_label("Application"); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup2), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_offline_add), (gpointer) MEDIA_APPLICATION); item2 = gtk_menu_item_new_with_label("Image"); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup2), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_offline_add), (gpointer) MEDIA_IMAGE); item2 = gtk_menu_item_new_with_label("Text"); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup2), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_offline_add), (gpointer) MEDIA_TEXT); item2 = gtk_menu_item_new_with_label("All Files"); gtk_widget_show(item2); gtk_container_add(GTK_CONTAINER(popup2), item2); gtk_signal_connect(GTK_OBJECT(item2), "activate", GTK_SIGNAL_FUNC(on_offline_add), (gpointer) MEDIA_NONE); } else { item = gtk_menu_item_new_with_label("Create Virtual Folder"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_create_virtual_activate), node); } 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("Expand Subtree"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_expand_activate), node); item = gtk_menu_item_new_with_label("Collapse Subtree"); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(popup), item); gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(on_collapse_activate), node); return popup; } static void on_delete_list_activate(GtkMenuItem * menuitem, gpointer user_data ATTR_UNUSED) { GtkLabel *label; char *s1; label = GTK_LABEL(GTK_BIN(menuitem)->child); s1 = label->label; lib_delete(s1); } static void on_load_list_activate(GtkMenuItem * menuitem, gpointer user_data ATTR_UNUSED) { GtkLabel *label; char *s1; label = GTK_LABEL(GTK_BIN(menuitem)->child); s1 = label->label; lib_share(lib_load_saved(s1), NULL); setup_preferences(P_SHARES); } GtkWidget *create_files_popup() { GtkWidget *popup; GtkWidget *menu1 = NULL; GtkWidget *menu2 = NULL; GtkWidget *item; GtkWidget *item1; GtkWidget *item2; GtkAccelGroup *popup_accels; char dirname[2048]; struct dirent *entry; struct stat buf; char filename[2048]; DIR *dir; int cnt = 0; sprintf(dirname, "%s%cshare", global.options.config_dir, DIR_SEP); popup = gtk_menu_new(); popup_accels = gtk_menu_ensure_uline_accel_group(GTK_MENU(popup)); item1 = gtk_menu_item_new_with_label("Delete List"); gtk_widget_show(item1); gtk_container_add(GTK_CONTAINER(popup), item1); item = gtk_menu_item_new(); gtk_widget_show(item); gtk_widget_set_sensitive(item, FALSE); gtk_container_add(GTK_CONTAINER(popup), item); item2 = gtk_menu_item_new_with_label("Load List"); gtk_widget_show(item2); // if (lib_is_busy()) gtk_widget_set_sensitive(item2, FALSE); gtk_container_add(GTK_CONTAINER(popup), item2); if ((dir = opendir(dirname)) == NULL) { g_warning("could not open dir [%s]", dirname); } else { while ((entry = readdir(dir)) != NULL) { // if (!strncmp(entry->d_name, ".", 1)) continue; // if (!strncmp(entry->d_name, "..", 2)) continue; sprintf(filename, "%s/%s", dirname, entry->d_name); stat(filename, &buf); if (S_ISREG(buf.st_mode)) { if (!cnt) { menu1 = gtk_menu_new(); gtk_widget_show(menu1); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item1), menu1); menu2 = gtk_menu_new(); gtk_widget_show(menu2); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item2), menu2); } item = gtk_menu_item_new_with_label(entry->d_name); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu1), item); gtk_signal_connect(GTK_OBJECT(item), "activate", on_delete_list_activate, NULL); item = gtk_menu_item_new_with_label(entry->d_name); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu2), item); gtk_signal_connect(GTK_OBJECT(item), "activate", on_load_list_activate, NULL); cnt++; } } closedir(dir); } if (!cnt) { gtk_widget_set_sensitive(item1, FALSE); gtk_widget_set_sensitive(item2, FALSE); // gtk_widget_set_sensitive(item3, FALSE); } return popup; } char* calc_time(int val, time_t* tim) { static char str[128]; time_t offset; switch (val) { case 1: offset = 60; strcpy(str, "1 minute"); break; case 2: offset = 300; strcpy(str, "5 minutes"); break; case 3: offset = 30*60; strcpy(str, "30 minutes"); break; case 4: offset = 3600; strcpy(str, "1 hour"); break; case 5: offset = 3600*2; strcpy(str, "2 hours"); break; case 6: offset = 3600*5; strcpy(str, "5 hours"); break; case 7: offset = 3600*12; strcpy(str, "12 hours"); break; case 8: offset = 86400; strcpy(str, "1 day"); break; case 9: offset = 86400*2; strcpy(str, "2 days"); break; case 10: offset = 86400*3; strcpy(str, "3 days"); break; case 11: offset = 86400*4; strcpy(str, "4 days"); break; case 12: offset = 86400*5; strcpy(str, "5 days"); break; case 13: offset = 86400*6; strcpy(str, "6 days"); break; case 14: offset = 86400*7; strcpy(str, "7 days"); break; case 15: offset = 86400*14; strcpy(str, "14 days"); break; case 16: offset = 86400*30; strcpy(str, "1 month"); break; case 17: offset = 86400*60; strcpy(str, "2 months"); break; case 18: offset = 86400*90; strcpy(str, "3 months"); break; case 19: offset = 86400*180; strcpy(str, "6 months"); break; case 20: offset = 86400*365; strcpy(str, "1 year"); break; case 21: offset = 86400*730; strcpy(str, "2 years"); break; default: offset = 0; strcpy(str, "0 seconds"); break; } *tim = offset; return str; } static void lib_set_mark_val(time_t val) { if (global.lib) { global.lib->mark = val; file_tree_mark(FILE_TREE(global.lib), 1); } } void on_lib_value_changed(GtkAdjustment *adjustment, gpointer user_data) { GtkLabel* label = user_data; time_t tim; char* text; text = calc_time(adjustment->value, &tim); global.options.lib_mark_val = adjustment->value; lib_set_mark_val(tim); if (label) gtk_label_set_text(GTK_LABEL(label), text); } static shared_folder_t* lib_search_folder(library_t* lib, char* name, int type) { GList* dlist; shared_folder_t* folder = NULL; if (!lib) return NULL; for (dlist = lib->shared_folder; dlist; dlist = dlist->next) { folder = dlist->data; if (!strcmp(folder->name, name) && folder->type == type) return folder; } return NULL; } shared_folder_t* lib_add_folder(library_t* lib, char* folder, int type) { shared_folder_t* sf; if (!lib) return NULL; sf = lib_search_folder(lib, folder, type); if (!sf) { sf = g_malloc(sizeof(*sf)); sf->name = g_strdup(folder); sf->type = type; lib->shared_folder = g_list_append(lib->shared_folder, sf); return sf; } return NULL; } int lib_compare_folder(library_t* lib1, library_t* lib2) { GList* dlist; shared_folder_t* folder; shared_folder_t* folder2; if (!lib1 || !lib2) return 1; for (dlist = lib1->shared_folder; dlist; dlist = dlist->next) { folder = dlist->data; folder2 = lib_search_folder(lib2, folder->name, folder->type); if (!folder2) return 1; } for (dlist = lib2->shared_folder; dlist; dlist = dlist->next) { folder = dlist->data; folder2 = lib_search_folder(lib1, folder->name, folder->type); if (!folder2) return 1; } return 0; }