/* 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 "lopster.h" #include "global.h" #include "userinfo.h" #include "support.h" #include "callbacks.h" #include "string_list.h" #include "subscription.h" #include "whois.h" #include "utils.h" #define INFO_LIFE 10 // days struct server_t; static GHashTable* UserInfo = NULL; /* static void user_info_destroy(user_info_t* userinfo) { if (!userinfo) return; if (userinfo->nick) g_free(userinfo->nick); if (userinfo->last_server) g_free(userinfo->last_server); g_free(userinfo); } */ user_info_t* user_info_new(char* user) { user_info_t* info; info = g_malloc(sizeof(*info)); info->last_server = NULL; info->nick = g_strdup(user); info->cur[0] = 0; info->cur[1] = 0; info->real_cur[0] = 0; info->real_cur[1] = 0; info->max[0] = -1; info->max[1] = -1; info->limit[0] = 0; info->limit[1] = 0; info->bytes[0] = 0; info->bytes[1] = 0; info->ignore_global[0] = 0; info->ignore_global[1] = 0; info->linespeed = -1; info->timestamp = 1; info->last_seen = global.current_time; info->shares = -1; info->remotes = 0; info->client = C_UNKNOWN; if (!UserInfo) { UserInfo = g_hash_table_new((GHashFunc)g_str_hash, (GCompareFunc)g_str_equal); } g_hash_table_insert(UserInfo, info->nick, info); return info; } int user_info_is_default(user_info_t* info) { if (info->max[0] == -1 && info->max[1] == -1 && info->limit[0] == 0 && info->limit[1] == 0 && info->ignore_global[0] == 0 && info->ignore_global[1] == 0) return 1; else return 0; } static void user_info_save_entry(const char* nick, user_info_t* info, FILE* file) { (void)nick; // dont save nicks that are expired and have default settings if (global.current_time - info->last_seen > 60*60*24*INFO_LIFE && user_info_is_default(info)) return; qfprintf(file, "%s %d %d %ld %ld %d %d %lu %S\n", info->nick, info->max[0], info->max[1], info->limit[0], info->limit[1], info->ignore_global[0], info->ignore_global[1], info->last_seen, info->last_server?info->last_server:""); } void user_info_save() { char *fname; char *fname_new; FILE *fd; fname = g_strdup_printf("%s/userinfo.list", global.options.config_dir); fname_new = g_strdup_printf("%s/access.list.new", global.options.config_dir); if ((fd = fopen(fname_new, "w")) == NULL) { g_warning("Could not write [%s]\n", fname); g_free(fname); g_free(fname_new); return; } g_hash_table_foreach(UserInfo, (GHFunc)user_info_save_entry, fd); if (!ferror(fd)) rename(fname_new, fname); else g_warning("Could not write [%s]\n", fname); fclose(fd); g_free(fname); g_free(fname_new); } void user_info_load() { FILE *fd; char *fname; char* user; char* max1, *max2; char* limit1, *limit2; char* ignore1, *ignore2; user_info_t* userinfo; char* seen; char* server; time_t last_seen; char line[2048]; // printf("user_info_load(): %ld\n", time(NULL)); fname = g_strdup_printf("%s/userinfo.list", global.options.config_dir); if ((fd = fopen(fname, "r")) == NULL) { g_free(fname); return; } g_free(fname); while (mfgets(line, sizeof(line), fd)) { user = arg(line, 2); max1 = arg(NULL, 2); max2 = arg(NULL, 2); limit1 = arg(NULL, 2); limit2 = arg(NULL, 2); ignore1 = arg(NULL, 2); ignore2 = arg(NULL, 2); seen = arg(NULL, 2); server = arg(NULL, 2); if (!ignore2) continue; if (seen) last_seen = strtol(seen, NULL, 10); else last_seen = global.current_time; if (global.current_time - last_seen > 60*60*24*INFO_LIFE) continue; userinfo = user_info_new(user); userinfo->max[0] = atoi(max1); if (userinfo->max[0] == -2) userinfo->max[0] = 0; userinfo->max[1] = atoi(max2); if (userinfo->max[1] == -2) userinfo->max[1] = 0; userinfo->limit[0] = strtol(limit1, NULL, 10); userinfo->limit[1] = strtol(limit2, NULL, 10); userinfo->ignore_global[0] = atoi(ignore1); userinfo->ignore_global[1] = atoi(ignore2); userinfo->last_seen = last_seen; userinfo->last_server = server?g_strdup(server):NULL; } fclose(fd); return; } user_info_t* user_info_search(char* user) { user_info_t* info; info = g_hash_table_lookup(UserInfo, user); return info; } int user_info_priority(user_info_t* userinfo, int* class) { subscription_t* sub; if (string_list_search(LIST_FRIEND, userinfo->nick)) { if (class) *class = PRI_FRIEND; return global.options.upload_priority[PRI_FRIEND]; } sub = subscription_user_search(userinfo->nick); if (sub && sub->friend_while_subs) { if (class) *class = PRI_FRIEND; return global.options.upload_priority[PRI_FRIEND]; } if (userinfo->real_cur[0] > 0) { if (class) *class = PRI_DOWNLOAD; return global.options.upload_priority[PRI_DOWNLOAD]; } if (userinfo->shares == 0) { if (class) *class = PRI_NONE; return global.options.upload_priority[PRI_NONE]; } else { if (class) *class = PRI_SHARE; return global.options.upload_priority[PRI_SHARE]; } return PRI_NONE; } void user_info_get(user_info_t* userinfo, net_t* net) { // check timestamp. if (userinfo->timestamp && global.current_time - userinfo->timestamp > 60*60) { userinfo->timestamp = 0; // mark whois_request(net, userinfo->nick, WHOIS_NONE); } } void user_info_show(user_info_t* userinfo, int download, int active) { GtkWidget* area; GtkWidget* spin; int posx; int posy; long limit; char* ss; int width, height; int upload = !download; char str[1024]; GtkStyle* style; if (download) { limit = global.down_width.limit; area = lookup_widget(global.win, "drawingarea12"); spin = lookup_widget(global.win, "spinbutton15"); style = area->style; } else { limit = global.up_width.limit; area = lookup_widget(global.win, "drawingarea11"); spin = lookup_widget(global.win, "spinbutton49"); style = area->style; } if (!area->window) return; if (limit <= 0) limit = 1024*80; gtk_object_set_data(GTK_OBJECT(area), "userinfo", userinfo); gtk_object_set_data(GTK_OBJECT(spin), "userinfo", userinfo); width = area->allocation.width; height = area->allocation.height; gdk_draw_rectangle(area->window, style->bg_gc[0], TRUE, 0, 0, width, height); if (!userinfo) return; if (!active) gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), (gfloat) (userinfo->max[upload])); posx = (width - 4) * userinfo->limit[upload] / limit; if (posx > width-4) posx = width-4; if (posx) gdk_draw_rectangle(area->window, style->bg_gc[3], TRUE, 2, 2, posx, height-4); if (!active) { ss = userinfo->nick; } else if (userinfo->limit[upload] == 0) { strcpy(str, "No bandwidth limit"); ss = str; } else { ss = print_speed(str, userinfo->limit[upload], 1); } posx = (width - 4 - gdk_string_width(style->font, ss))/2; posy = (height + style->font->ascent - 4)/2+1; gdk_draw_text (area->window, style->font, style->fg_gc[3], posx, posy, ss, strlen (ss)); } /* this function could be dangerous, as it does delete user infos that * might be still in use somewhere else (actually this might only * happen if uptime > INFO_FILE (10 days) */ // deactivated at the moment, cleanup is done at exit /* int user_info_cleanup(gpointer data ATTR_UNUSED) { GList* dlist; user_info_t* info; GList* res = NULL; return 0; for (dlist = global.userinfo; dlist; dlist = dlist->next) { info = dlist->data; if (global.current_time - info->last_seen > 60*60*24*INFO_LIFE) res = g_list_prepend(res, dlist); } // not finished yet. return 1; } */ user_info_t* user_info_detect(net_t* net, char* user) { user_info_t *user_info; user_info = user_info_search(user); if (!user_info) user_info = user_info_new(user); user_info_get(user_info, net); return user_info; } static void ui_fe(char* key, user_info_t* info, void** data) { UserInfoFunc func = data[0]; void* user_data = data[1]; (void)key; if (info) func(info, user_data); } void user_info_foreach(UserInfoFunc func, void* data) { static void* array[2]; if (!UserInfo) return; array[0] = func; array[1] = data; g_hash_table_foreach(UserInfo, (GHFunc)ui_fe, array); }