/*****************************************************************************/ /* Klavaro - a flexible touch typing tutor */ /* Copyright (C) 2005, 2006, 2007, 2008 Felipe Castro */ /* Copyright (C) 2009 Free Software Foundation */ /* */ /* This program is free software, licensed under the terms of the GNU */ /* General Public License as published by the Free Software Foundation, */ /* either version 3 of the License, or (at your option) any later version. */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ /*****************************************************************************/ /* * Contest for fluidness performance */ #include #include #include #include #include #include #include #include #include #include #include #include "auxiliar.h" #include "main.h" #include "translation.h" #include "top10.h" /************************************************** * Variables */ Statistics top10_local[10]; Statistics top10_global[10]; GKeyFile *keyfile = NULL; /************************************************** * Functions */ void top10_init () { gint i; gchar *str; GtkListStore *list; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeView *tv; GtkTreeIter iter; GtkComboBox *cmb; renderer = gtk_cell_renderer_text_new (); /* Main info on treeview */ tv = GTK_TREE_VIEW (get_wg ("treeview_top10_1")); list = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (tv, GTK_TREE_MODEL (list)); column = gtk_tree_view_column_new_with_attributes ("#", renderer, "text", 0, NULL); gtk_tree_view_append_column (tv, column); column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer, "text", 1, NULL); gtk_tree_view_append_column (tv, column); column = gtk_tree_view_column_new_with_attributes (_("Score"), renderer, "text", 2, NULL); gtk_tree_view_append_column (tv, column); for (i = 0; i < 10; i++) { str = g_strdup_printf ("%02i", i + 1); gtk_list_store_append (list, &iter); gtk_list_store_set (list, &iter, 0, str, 1, "--------------------------", 2, "0.000", -1); g_free (str); } /* Extra info on treeview */ tv = GTK_TREE_VIEW (get_wg ("treeview_top10_2")); list = gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model (tv, GTK_TREE_MODEL (list)); column = gtk_tree_view_column_new_with_attributes (_("Accuracy"), renderer, "text", 0, NULL); gtk_tree_view_append_column (tv, column); column = gtk_tree_view_column_new_with_attributes (_("Speed"), renderer, "text", 1, NULL); gtk_tree_view_append_column (tv, column); column = gtk_tree_view_column_new_with_attributes (_("Fluidity"), renderer, "text", 2, NULL); gtk_tree_view_append_column (tv, column); column = gtk_tree_view_column_new_with_attributes (_("Chars"), renderer, "text", 3, NULL); gtk_tree_view_append_column (tv, column); column = gtk_tree_view_column_new_with_attributes (_("When"), renderer, "text", 4, NULL); gtk_tree_view_append_column (tv, column); for (i = 0; i < 10; i++) { gtk_list_store_append (list, &iter); gtk_list_store_set (list, &iter, 0, "--", 1, "--", 2, "--", 3, "--", 4, "--", -1); } /* Set modules combo */ cmb = GTK_COMBO_BOX (get_wg ("combobox_stat_module")); for (i = 0; i < 4; i++) gtk_combo_box_remove_text (cmb, 0); str = g_strdup_printf ("1 - %s", _("Basic course")); gtk_combo_box_append_text (cmb, str); g_free (str); str = g_strdup_printf ("2 - %s", _("Adaptability")); gtk_combo_box_append_text (cmb, str); g_free (str); str = g_strdup_printf ("3 - %s", _("Speed")); gtk_combo_box_append_text (cmb, str); g_free (str); str = g_strdup_printf ("4 - %s", _("Fluidity")); gtk_combo_box_append_text (cmb, str); g_free (str); } void top10_message (gchar * msg) { static gboolean init = TRUE; if (!init) gtk_statusbar_pop (GTK_STATUSBAR (get_wg ("statusbar_top10_message")), 0); if (msg == NULL) { gtk_statusbar_push (GTK_STATUSBAR (get_wg ("statusbar_top10_message")), 0, ""); return; } gtk_statusbar_push (GTK_STATUSBAR (get_wg ("statusbar_top10_message")), 0, msg); } #define NOBODY "xxx" void top10_clean_stat (gint i, gboolean locally) { Statistics *top10; top10 = locally ? top10_local : top10_global; if (i > 9) return; top10[i].lang[0] = 'x'; top10[i].lang[1] = 'x'; top10[i].genv = 'x'; top10[i].when = 0; top10[i].nchars = MIN_CHARS_TO_LOG; top10[i].accur = 0.0; top10[i].velo = 0.0; top10[i].fluid = 0.0; top10[i].score = 0.0; top10[i].name_len = strlen (NOBODY); strcpy (top10[i].name, NOBODY); } void top10_init_stats (gboolean locally) { gint i; Statistics *top10; top10 = locally ? top10_local : top10_global; for (i = 0; i < 10; i++) top10_clean_stat (i, locally); } void top10_insert_stat (Statistics * stat, gint i, gboolean locally) { gint j; Statistics *top10; top10 = locally ? top10_local : top10_global; if (i > 9) return; for (j = 8; j >= i; j--) memmove (&top10[j + 1], &top10[j], sizeof (Statistics)); memmove (&top10[i], stat, sizeof (Statistics)); } gboolean top10_compare_insert_stat (Statistics * stat, gboolean locally) { gint i, j; gint statnamelen; gchar *pos; Statistics *top10; top10 = locally ? top10_local : top10_global; statnamelen = strlen (stat->name); pos = strrchr (stat->name, '['); if (pos != NULL) if (pos > stat->name && *(pos - 1) == ' ') { statnamelen = pos - stat->name - 1; if (statnamelen < 1) statnamelen = strlen (stat->name); } for (i = 0; i < 10; i++) { if (stat->score > top10[i].score) { for (j = i - 1; j >= 0; j--) { if (strncmp (stat->name, top10[j].name, statnamelen) == 0) return (FALSE); } for (j = i; j < 10; j++) { if (strncmp (stat->name, top10[j].name, statnamelen) == 0 && stat->score > 0) { top10_delete_stat (j, locally); j--; } } top10_insert_stat (stat, i, locally); return (TRUE); } } return (FALSE); } void top10_delete_stat (gint i, gboolean locally) { gint j; Statistics *top10; top10 = locally ? top10_local : top10_global; if (i > 9) return; for (j = i; j < 9; j++) memmove (&top10[j], &top10[j + 1], sizeof (Statistics)); top10_clean_stat (9, locally); } gfloat top10_calc_score_old (Statistics * stat) { gfloat score; // Don't touch this anymore! score = (6 * stat->velo + 3 * stat->accur + stat->fluid) / 100; return (score); } gfloat top10_calc_score (Statistics * stat) { gfloat score; // Don't touch this anymore! (touched: new_WPM = 1.2 old_WPM) score = (6 * stat->velo / 1.2 + 3 * stat->accur + stat->fluid) / 100; return (score); } gboolean top10_validate_stat (Statistics * stat) { if (stat->score > 10.0 || stat->score < 0.0) { g_message ("Invalid score (%g): it must be between 0 and 10", stat->score); return (FALSE); } if ((stat->score - top10_calc_score (stat) > 1.0e-5) && (stat->score - top10_calc_score_old (stat) > 1.0e-5)) { g_message ("Invalid score (%g): did you try to edit the scores file?", stat->score); return (FALSE); } if (stat->fluid > 95) { g_message ("Invalid score (fluidness = %g): robots shouldn't compete with humans...", stat->fluid); return (FALSE); } return (TRUE); } gchar * top10_get_score_file (gboolean locally, gint lang) { gchar *tmp = NULL; gchar *ksc; if (lang < 0) tmp = main_preferences_get_string ("interface", "language"); else tmp = g_strdup (trans_get_code (lang)); if (tmp == NULL) tmp = g_strdup ("en"); if (tmp[0] == 'C') ksc = g_strdup (locally ? "local_en.ksc" : "global_en.ksc"); else ksc = g_strdup_printf ("%s_%c%c.ksc", locally ? "local" : "global", tmp[0], tmp[1]); g_free (tmp); return (ksc); } static void top10_merge_stats_from_file (gchar * file) { gint i, j, n; FILE *fh; Statistics top10; fh = g_fopen (file, "r"); if (fh == NULL) return; for (i = 0; i < 10; i++) { /* lang[0] */ top10.lang[0] = getc (fh); if (!g_ascii_isalpha (top10.lang[0])) { g_message ("Problem: lang[0] = %c", top10.lang[0]); break; } /* lang[1] */ top10.lang[1] = getc (fh); if (!g_ascii_isalpha (top10.lang[1])) { top10.lang[0] = 'e'; top10.lang[1] = 'o'; } /* genv */ top10.genv = getc (fh); if (top10.genv != 'x' && top10.genv != 'w') { g_message ("Problem: genv = %c", top10.genv); break; } /* when */ n = fread (&top10.when, sizeof (time_t), 1, fh); if (n == 0) { g_message ("Problem: when = %lu", top10.when); break; } /* nchars */ n = fread (&top10.nchars, sizeof (gint), 1, fh); if (n == 0 || top10.nchars < MIN_CHARS_TO_LOG) { g_message ("Problem: nchars = %i, < %i", top10.nchars, MIN_CHARS_TO_LOG); break; } /* accur */ n = fread (&top10.accur, sizeof (gfloat), 1, fh); if (n == 0 || top10.accur < 0 || top10.accur > 100) { g_message ("Problem: accur = %f <> [0, 100]", top10.accur); break; } /* velo */ n = fread (&top10.velo, sizeof (gfloat), 1, fh); if (n == 0 || top10.velo < 0 || top10.velo > 300) { g_message ("Problem: velo = %f <> [0, 300]", top10.velo); break; } /* fluid */ n = fread (&top10.fluid, sizeof (gfloat), 1, fh); if (n == 0 || top10.fluid < 0 || top10.fluid > 100) { g_message ("Problem: fluid = %f <> [0, 100]", top10.fluid); break; } /* score */ n = fread (&top10.score, sizeof (gfloat), 1, fh); if (n == 0 || top10.score < 0 || top10.score > 20) { g_message ("Problem: score = %f <> [0, 20]", top10.score); break; } /* name_len */ n = fread (&top10.name_len, sizeof (gint), 1, fh); if (n == 0 || top10.name_len < 0 || top10.name_len > MAX_NAME_LEN) { g_message ("Problem: name_len = %i <> [0, MAX_NAME_LEN]", top10.name_len); break; } /* name */ n = fread (&top10.name, sizeof (gchar), top10.name_len, fh); top10.name[top10.name_len] = '\0'; if (!g_utf8_validate (top10.name, -1, NULL)) { for (j = 0; j < top10.name_len; j++) if (!g_ascii_isalpha (top10.name[j])) top10.name[j] = '?'; } top10_compare_insert_stat (&top10, TRUE); } fclose (fh); } gboolean top10_read_stats_from_file (gboolean locally, gchar * file) { gint i, j, n; gboolean success; FILE *fh; Statistics *top10; top10 = locally ? top10_local : top10_global; fh = g_fopen (file, "r"); if (fh == NULL) return FALSE; for (i = 0; i < 10; i++) { success = FALSE; /* lang[0] */ top10[i].lang[0] = fgetc (fh); if (!g_ascii_isalpha (top10[i].lang[0])) { g_message ("Problem: lang[0] = %c", top10[i].lang[0]); break; } /* lang[1] */ top10[i].lang[1] = fgetc (fh); if (!g_ascii_isalpha (top10[i].lang[1])) { top10[i].lang[0] = 'e'; top10[i].lang[1] = 'o'; } /* genv */ top10[i].genv = fgetc (fh); if (top10[i].genv != 'x' && top10[i].genv != 'w') { g_message ("Problem: genv = %c", top10[i].genv); break; } /* when */ n = fread (&top10[i].when, sizeof (time_t), 1, fh); if (n == 0) { g_message ("Problem: when = %lu", top10[i].when); break; } /* nchars */ n = fread (&top10[i].nchars, sizeof (gint), 1, fh); if (n == 0 || top10[i].nchars < MIN_CHARS_TO_LOG) { g_message ("Problem: nchars = %i, < %i", top10[i].nchars, MIN_CHARS_TO_LOG); break; } /* accur */ n = fread (&top10[i].accur, sizeof (gfloat), 1, fh); if (n == 0 || top10[i].accur < 0 || top10[i].accur > 100) { g_message ("Problem: accur = %f <> [0, 100]", top10[i].accur); break; } /* velo */ n = fread (&top10[i].velo, sizeof (gfloat), 1, fh); if (n == 0 || top10[i].velo < 0 || top10[i].velo > 300) { g_message ("Problem: velo = %f <> [0, 300]", top10[i].velo); break; } /* fluid */ n = fread (&top10[i].fluid, sizeof (gfloat), 1, fh); if (n == 0 || top10[i].fluid < 0 || top10[i].fluid > 100) { g_message ("Problem: fluid = %f <> [0, 100]", top10[i].fluid); break; } /* score */ n = fread (&top10[i].score, sizeof (gfloat), 1, fh); if (n == 0 || top10[i].score < 0 || top10[i].score > 20) { g_message ("Problem: score = %f <> [0, 20]", top10[i].score); break; } /* name_len */ n = fread (&top10[i].name_len, sizeof (gint), 1, fh); if (n == 0 || top10[i].name_len < 0 || top10[i].name_len > MAX_NAME_LEN) { g_message ("Problem: name_len = %i <> [0, MAX_NAME_LEN]", top10[i].name_len); break; } /* name */ n = fread (&top10[i].name, sizeof (gchar), top10[i].name_len, fh); top10[i].name[top10[i].name_len] = '\0'; if (!g_utf8_validate (top10[i].name, -1, NULL)) { for (j = 0; j < top10[i].name_len; j++) if (!g_ascii_isalpha (top10[i].name[j])) top10[i].name[j] = '?'; } success = TRUE; } fclose (fh); return (success); } void top10_read_stats (gboolean locally, gint lang) { gchar *local_ksc; gchar *tmp; gchar *uname; gchar *stat_dir; gboolean success; GDir *home; Statistics *top10; top10 = locally ? top10_local : top10_global; top10_init_stats (locally); local_ksc = top10_get_score_file (locally, lang); tmp = g_build_filename (main_path_score (), local_ksc, NULL); if (!top10_read_stats_from_file (locally, tmp)) { g_message ("Could not read the scores file '%s'.\n Creating a blank one.", tmp); top10_init_stats (locally); top10_write_stats (locally, lang); } g_free (tmp); if (!locally) { g_free (local_ksc); return; } /* Go search other users' subdirs */ tmp = strchr (main_path_stats (), G_DIR_SEPARATOR); if (tmp) tmp = strchr (tmp + 1, G_DIR_SEPARATOR); if (tmp) tmp = strchr (tmp + 1, G_DIR_SEPARATOR); if (tmp) { stat_dir = tmp + 1; home = g_dir_open ("/home", 0, NULL); } else home = NULL; success = FALSE; if (home) { while ((uname = (gchar*) g_dir_read_name (home))) { if (g_str_equal (uname, "root")) continue; if (g_str_equal (uname, "lost+found")) continue; if (g_str_equal (uname, g_get_user_name ())) continue; tmp = g_build_filename ("/home", uname, stat_dir, "ksc", local_ksc, NULL); if (g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) { top10_merge_stats_from_file (tmp); success = TRUE; } g_free (tmp); } g_dir_close (home); } g_free (local_ksc); if (success) top10_write_stats (TRUE, -1); } void top10_write_stats (gboolean locally, gint lang) { gint i; gchar *filename; gchar *lsfile; FILE *fh; Statistics *top10; top10 = locally ? top10_local : top10_global; if (!g_file_test (main_path_score (), G_FILE_TEST_IS_DIR)) g_mkdir_with_parents (main_path_score (), DIR_PERM); filename = top10_get_score_file (locally, lang); lsfile = g_build_filename (main_path_score (), filename, NULL); fh = g_fopen (lsfile, "w"); if (fh == NULL) { g_warning ("Could not write the scores file in %s", main_path_score ()); g_free (filename); g_free (lsfile); return; } for (i = 0; i < 10; i++) { fputc (top10[i].lang[0], fh); fputc (top10[i].lang[1], fh); fputc (top10[i].genv, fh); fwrite (&top10[i].when, sizeof (time_t), 1, fh); fwrite (&top10[i].nchars, sizeof (gint), 1, fh); fwrite (&top10[i].accur, sizeof (gfloat), 1, fh); fwrite (&top10[i].velo, sizeof (gfloat), 1, fh); fwrite (&top10[i].fluid, sizeof (gfloat), 1, fh); fwrite (&top10[i].score, sizeof (gfloat), 1, fh); fwrite (&top10[i].name_len, sizeof (gint), 1, fh); if (top10[i].name && top10[i].name_len > 0) fputs (top10[i].name, fh); } fputs ("KLAVARO!", fh); fclose (fh); g_free (filename); g_free (lsfile); } /* Test function to show every field of a scoring record, at the terminal */ void top10_show_stat (Statistics * stat) { g_print ("Language: %c%c\n", stat->lang[0], stat->lang[1]); g_print ("Graphical environment: %s\n", stat->genv == 'x' ? "Linux" : "Windows"); g_print ("When: %li\n", stat->when); g_print ("# of characters: %i\n", stat->nchars); g_print ("Accuracy: %2.1f\n", stat->accur); g_print ("Velocity: %2.1f\n", stat->velo); g_print ("Fluidness: %2.1f\n", stat->fluid); g_print ("Score: %05.1f\n", stat->score); g_print ("Name length: %i\n", stat->name_len); g_print ("Name: %s\n", stat->name); } void top10_show_stats (gboolean locally) { gint i; gboolean success; gchar *tmp; gchar *url; gchar *accur; gchar *velo; gchar *fluid; gchar *nchars; gchar *date; struct tm *ltime; Statistics *top10; GtkListStore *list1; GtkListStore *list2; GtkTreeIter iter1; GtkTreeIter iter2; top10 = locally ? top10_local : top10_global; top10_read_stats (locally, -1); top10_read_stats (!locally, -1); /* Set layout */ if (top10[0].score == 0.0) { top10_message (_("Empty ranking. Please practice fluidness.")); gtk_widget_set_sensitive (get_wg ("treeview_top10_1"), FALSE); gtk_widget_set_sensitive (get_wg ("treeview_top10_2"), FALSE); } else { gtk_widget_set_sensitive (get_wg ("treeview_top10_1"), TRUE); gtk_widget_set_sensitive (get_wg ("treeview_top10_2"), TRUE); } gtk_widget_set_sensitive (get_wg ("button_top10_update"), !locally); if (top10_local[0].score == 0.0) gtk_widget_set_sensitive (get_wg ("button_top10_publish"), FALSE); else gtk_widget_set_sensitive (get_wg ("button_top10_publish"), !locally); /* Set web link */ tmp = main_preferences_get_string ("interface", "language"); if (tmp[0] == 'C') { g_free (tmp); tmp = g_strdup ("en"); } url = g_strdup_printf ("http://" DOWNHOST "/%c%c/", tmp[0], tmp[1]); gtk_widget_set_tooltip_text (get_wg ("button_top10_go_www"), url); g_free (tmp); g_free (url); /* Print the ranking */ list1 = GTK_LIST_STORE ( gtk_tree_view_get_model (GTK_TREE_VIEW (get_wg ("treeview_top10_1"))) ); list2 = GTK_LIST_STORE ( gtk_tree_view_get_model (GTK_TREE_VIEW (get_wg ("treeview_top10_2"))) ); success = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list1), &iter1); success = (success && gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list2), &iter2)); if (! success) { g_warning ("not able to set Top10 Treeviews"); return; } for (i = 0; i < 10; i++) { if (top10[i].score == 0) { gtk_list_store_set (list1, &iter1, 1, "", 2, "", -1); gtk_list_store_set (list2, &iter2, 0, "", 1, "", 2, "", 3, "", 4, "", -1); } else { /* First treeview: main info */ tmp = g_strdup_printf ("%3.4f", top10[i].score); gtk_list_store_set (list1, &iter1, 1, top10[i].name, 2, tmp, -1); g_free (tmp); /* Second treeview: further info */ accur = g_strdup_printf ("%2.1f", top10[i].accur); velo = g_strdup_printf ("%2.1f", top10[i].velo); fluid = g_strdup_printf ("%2.1f", top10[i].fluid); nchars = g_strdup_printf ("%i", top10[i].nchars); ltime = localtime (&top10[i].when); date = g_strdup_printf ("%i-%2.2i-%2.2i %02i:%02i", (ltime->tm_year) + 1900, (ltime->tm_mon) + 1, (ltime->tm_mday), (ltime->tm_hour), (ltime->tm_min)); gtk_list_store_set (list2, &iter2, 0, accur, 1, velo, 2, fluid, 3, nchars, 4, date, -1); g_free (accur); g_free (velo); g_free (fluid); g_free (nchars); g_free (date); } gtk_tree_model_iter_next (GTK_TREE_MODEL (list1), &iter1); gtk_tree_model_iter_next (GTK_TREE_MODEL (list2), &iter2); } } gboolean top10_global_update (gpointer data) { gboolean fail; gchar *tmp; gchar *ksc; gchar *host; gchar *command; GtkImage *img; gpointer gp; CURL *curl; FILE *fh; gp = data; img = GTK_IMAGE (get_wg ("image_top10_update")); top10_message (NULL); if (!main_curl_ok ()) { tmp = g_strconcat (_("Not able to download files"), ": 'libcurl' ", _("not found"), ". ", _("Are you sure you have it installed in your system?"), NULL); top10_message (tmp); g_free (tmp); gtk_image_set_from_stock (img, "gtk-goto-bottom", GTK_ICON_SIZE_BUTTON); return FALSE; } /************************************************** * Download from downhost */ host = g_strdup (DOWNHOST); ksc = top10_get_score_file (GLOBAL, -1); if (! (curl = curl_easy_init ()) ) { g_message ("Not able to initialize 'curl'"); gtk_image_set_from_stock (img, "gtk-goto-bottom", GTK_ICON_SIZE_BUTTON); g_free (host); return FALSE; } if (!g_file_test (main_path_score (), G_FILE_TEST_IS_DIR)) g_mkdir_with_parents (main_path_score (), DIR_PERM); tmp = g_build_filename (main_path_score (), ksc, NULL); fail = TRUE; command = g_strdup_printf ("http://%s/%s", host, ksc); if ( (fh = g_fopen (tmp, "wb")) ) { //curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); curl_easy_setopt (curl, CURLOPT_TIMEOUT, TIMEOUT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME); curl_easy_setopt (curl, CURLOPT_URL, command); curl_easy_setopt (curl, CURLOPT_WRITEDATA, fh); fail = curl_easy_perform (curl); fclose (fh); } curl_easy_cleanup (curl); g_free (command); g_free (host); if (fail) { top10_message (_("Could not download file from the host server.")); gtk_image_set_from_stock (img, "gtk-goto-bottom", GTK_ICON_SIZE_BUTTON); g_free (ksc); g_free (tmp); return FALSE; } if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) g_message ("No file downloaded from the host server."); gtk_image_set_from_stock (img, "gtk-goto-bottom", GTK_ICON_SIZE_BUTTON); g_free (tmp); g_free (ksc); if (gtk_combo_box_get_active (GTK_COMBO_BOX (get_wg ("combobox_top10"))) == 0) top10_show_stats (LOCAL); else top10_show_stats (GLOBAL); return FALSE; } gboolean top10_global_publish (gpointer data) { gint i; gboolean success; gchar *tmp; gchar *ksc; gchar *host; gchar *path; gchar *username; gchar *url; gpointer gp; GtkImage *img; FILE *fh, *fh2; struct stat fs; CURL *curl; gp = data; fs.st_size = 0; img = GTK_IMAGE (get_wg ("image_top10_publish")); top10_message (NULL); if (!main_curl_ok ()) { tmp = g_strconcat (_("Not able to upload files"), ": 'libcurl' ", _("not found"), ". ", _("Are you sure you have it installed in your system?"), NULL); top10_message (tmp); g_free (tmp); gtk_image_set_from_stock (img, "gtk-goto-top", GTK_ICON_SIZE_BUTTON); return FALSE; } if (! (curl = curl_easy_init ())) { g_message ("Not able to initialize curl session"); gtk_image_set_from_stock (img, "gtk-goto-top", GTK_ICON_SIZE_BUTTON); return FALSE; } /************************************************** * Upload to uphost, updating local ranking */ host = g_strdup (CGI_SERVER); tmp = main_preferences_get_string ("interface", "language"); if (tmp[0] == 'C') { g_free (tmp); tmp = g_strdup ("en"); } ksc = g_strdup_printf ("local_%c%c.ksc", tmp[0], tmp[1]); //path = g_build_filename ("/var/games/klavaro/", ksc, NULL); path = g_build_filename (main_path_score (), ksc, NULL); g_free (ksc); g_stat (path, &fs); username = g_strdup (g_get_real_name ()); username = g_strdelimit (username, " ", '_'); if (strlen (username) == 0) { g_free (username); username = g_strdup (g_get_user_name ()); } ksc = g_strdup_printf ("%s_%s_%c%c.ksc", username, g_get_host_name (), tmp[0], tmp[1]); url = g_strdup_printf ("http://%s?dosiernomo=%s&lingvo=%c%c", host, ksc, tmp[0], tmp[1]); g_free (username); g_free (host); g_free (ksc); g_free (tmp); //curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); curl_easy_setopt (curl, CURLOPT_TIMEOUT, TIMEOUT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME); curl_easy_setopt (curl, CURLOPT_UPLOAD, TRUE); curl_easy_setopt (curl, CURLOPT_INFILESIZE, (long) fs.st_size); curl_easy_setopt (curl, CURLOPT_URL, url); success = FALSE; if ( (fh = g_fopen (path, "rb")) ) { i = 0; while (1) { tmp = g_strdup_printf ("%s/klavaro_%03i.html", g_get_tmp_dir (), i++); if ((fh2 = g_fopen (tmp, "wb"))) break; g_free (tmp); } g_free (tmp); curl_easy_setopt (curl, CURLOPT_READDATA, fh); curl_easy_setopt (curl, CURLOPT_WRITEDATA, fh2); if (curl_easy_perform (curl)) g_message ("HTTP upload failed!"); else success = TRUE; fclose (fh); fclose (fh2); } curl_easy_cleanup (curl); g_free (path); g_free (url); gtk_image_set_from_stock (img, "gtk-goto-top", GTK_ICON_SIZE_BUTTON); if (!success) top10_message (_("Could not upload/download scores.")); else g_idle_add ((GSourceFunc) top10_global_update, NULL); return FALSE; } #define MAX_KSC_FILES 200 #define MAX_LANGS 79 void top10_global_rank () { glong i, j, k; gchar *file[MAX_KSC_FILES]; glong file_len; gboolean success; gboolean fail; gchar *msg; gchar *tmp; gchar *ksc; gchar *hostsub; gchar *host; gchar *subdir; gchar *user; gchar *pass; gchar *usrpas; gchar *command; gchar *command2; gchar **filelist; gboolean lang_update[MAX_LANGS]; FILE *fh; struct stat fs; CURL *curl; CURL *curl2; struct curl_slist *comms = NULL; if (!main_curl_ok ()) { g_warning ("Not able to upload files: 'libcurl' not installed."); return; } host = top10_get_host (); if (host == NULL) { g_message ("Nothing updated"); return; } user = top10_get_user ("upuser"); if (user == NULL) { g_message ("Nothing updated"); return; } pass = top10_get_pass ("uppass"); if (pass == NULL) { g_message ("Nothing updated"); return; } /* Get listing of files in the upload host */ fail = TRUE; command = g_strdup_printf ("ftp://%s/", host); curl = curl_easy_init (); if (curl) { tmp = g_strconcat (user, ":", pass, NULL); if ( (fh = g_fopen ("/tmp/.listing", "wb")) ) { //curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); curl_easy_setopt (curl, CURLOPT_FTPLISTONLY, 1); curl_easy_setopt (curl, CURLOPT_WRITEDATA, fh); curl_easy_setopt (curl, CURLOPT_USERPWD, tmp); curl_easy_setopt (curl, CURLOPT_URL, command); curl_easy_perform (curl); if (curl_easy_perform (curl)) g_message ("Retrieving .listing file failed!"); else fail = FALSE; fclose (fh); } curl_easy_cleanup (curl); g_free (tmp); } g_free (command); if (fail) { g_free (host); g_free (user); g_free (pass); g_warning ("Not able to connect to the uploading host"); return; } if (!g_file_get_contents ("/tmp/.listing", &tmp, NULL, NULL)) { g_free (host); g_free (user); g_free (pass); g_warning ("Not able to get a file list from the uploading host"); return; } g_unlink ("/tmp/.listing"); filelist = g_strsplit_set (tmp, "\n\r", 0); g_free (tmp); /* Select which files to download */ fail = FALSE; i = j = k = 0; while (filelist[i]) { if (! g_str_has_suffix (filelist[i], ".ksc")) { i++; continue; } for (k = 0; k < j; k++) if (g_str_equal (filelist[i], file[k])) { fail = TRUE; break; } if (fail) break; file[j++] = g_strdup (filelist[i]); if (j == MAX_KSC_FILES) { g_warning ("Maximum number of files to process reached: %li", j); break; } i++; } file_len = j; g_strfreev (filelist); /* Download the new files from upload host */ fail = TRUE; msg = g_strconcat (user, ":", pass, NULL); g_free (user); g_free (pass); if (! (curl = curl_easy_init ()) ) { g_free (host); g_free (msg); return; } //curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); curl_easy_setopt (curl, CURLOPT_USERPWD, msg); tmp = g_build_filename (g_get_tmp_dir (), "klavaro", NULL); g_mkdir (tmp, DIR_PERM); g_free (tmp); g_printf ("Downloaded:\n"); for (i = 0; i < file_len; i++) { command = g_strdup_printf ("ftp://%s/%s", host, file[i]); tmp = g_build_filename (g_get_tmp_dir (), "klavaro", file[i], NULL); if ( (fh = g_fopen (tmp, "wb")) ) { curl_easy_setopt (curl, CURLOPT_URL, command); curl_easy_setopt (curl, CURLOPT_WRITEDATA, fh); curl_easy_perform (curl); fclose (fh); g_printf ("\t%s\n", file[i]); } g_free (tmp); g_free (command); } curl_easy_cleanup (curl); g_free (msg); g_free (host); /* Rank local files into global files */ for (i = 0; trans_get_code (i) != NULL && i < MAX_LANGS; i++) { lang_update[i] = FALSE; if (i > 0) if (g_str_equal (trans_get_code (i), trans_get_code (i - 1))) continue; top10_read_stats (GLOBAL, i); tmp = g_strconcat ("_", trans_get_code (i), ".ksc", NULL); success = 0; for (j = 0; j < file_len; j++) { if (g_str_has_suffix (file[j], tmp)) { ksc = g_build_filename (g_get_tmp_dir (), "klavaro", file[j], NULL); if (!top10_read_stats_from_file (LOCAL, ksc)) g_message ("Invalid file: %s", ksc); else { for (k = 0; k < 10; k++) { if (!top10_validate_stat (&top10_local[k])) continue; if (top10_compare_insert_stat (&top10_local[k], GLOBAL)) { lang_update[i] = TRUE; success++; } } } msg = g_build_filename (g_get_tmp_dir (), file[j], NULL); if (g_rename (ksc, msg)) g_unlink (ksc); g_free (ksc); g_free (msg); } } g_free (tmp); if (success) top10_write_stats (GLOBAL, i); } tmp = g_build_filename (g_get_tmp_dir (), "klavaro", NULL); g_rmdir (tmp); g_free (tmp); /* Upload new rankings to download host */ hostsub = top10_get_host (); if (hostsub == NULL) { g_message ("Nothing updated"); return; } subdir = strchr (hostsub, '/'); if (!subdir) host = g_strdup (hostsub); else host = g_strndup (hostsub, subdir - hostsub); g_free (hostsub); user = top10_get_user ("downuser"); if (user == NULL) { g_message ("Nothing updated"); return; } pass = top10_get_pass ("downpass"); if (pass == NULL) { g_message ("Nothing updated"); return; } curl = curl_easy_init (); if (! curl) { g_message ("Nothing updated"); g_free (host); g_free (user); g_free (pass); return; } curl_easy_setopt (curl, CURLOPT_UPLOAD, TRUE); curl_easy_setopt (curl, CURLOPT_TIMEOUT, TIMEOUT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME); curl2 = curl_easy_init (); if (!curl2) { g_message ("Nothing updated in the new server"); g_free (host); g_free (user); g_free (pass); return; } curl_easy_setopt (curl2, CURLOPT_UPLOAD, TRUE); curl_easy_setopt (curl, CURLOPT_TIMEOUT, TIMEOUT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT); curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME); usrpas = g_strdup_printf ("%s:%s", user, pass); curl_easy_setopt (curl, CURLOPT_USERPWD, usrpas); //curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); g_printf ("Uploaded:\n"); for (i = 0; trans_get_code (i) != NULL && i < MAX_LANGS; i++) { if (i > 0) if (g_str_equal (trans_get_code (i), trans_get_code (i - 1))) continue; if (lang_update[i] == FALSE) continue; msg = g_strconcat ("global_", trans_get_code (i), ".ksc", NULL); ksc = g_build_filename (main_path_score (), msg, NULL); command = g_strdup_printf ("ftp://%s/%s", host, msg); command2 = g_strdup_printf ("http://" CGI_SERVER "?dosiernomo=%s&lingvo=%s", msg, trans_get_code (i)); success = FALSE; if ( (fh = g_fopen (ksc, "rb"))) { fs.st_size = 0; g_stat (ksc, &fs); curl_easy_setopt (curl, CURLOPT_INFILESIZE, (long) fs.st_size); curl_easy_setopt (curl, CURLOPT_URL, command); curl_easy_setopt (curl, CURLOPT_READDATA, fh); curl_easy_setopt (curl2, CURLOPT_INFILESIZE, (long) fs.st_size); curl_easy_setopt (curl2, CURLOPT_URL, command2); curl_easy_setopt (curl2, CURLOPT_READDATA, fh); if (curl_easy_perform (curl)) g_message ("FTP upload failed!"); else success = TRUE; fseek (fh, 0, SEEK_SET); curl_easy_perform (curl2); g_printf ("\t%s\n", msg); fclose (fh); } g_free (msg); g_free (ksc); g_free (command); g_free (command2); } curl_easy_cleanup (curl); curl_easy_cleanup (curl2); g_free (host); g_free (user); g_free (pass); g_free (usrpas); /* Remove downloaded files in uphost */ host = top10_get_host (); if (host == NULL) { g_message ("Nothing updated"); return; } user = top10_get_user ("upuser"); if (user == NULL) { g_message ("Nothing updated"); return; } pass = top10_get_pass ("uppass"); if (pass == NULL) { g_message ("Nothing updated"); return; } curl = curl_easy_init (); if (! curl) { g_message ("Nothing updated"); g_free (host); g_free (user); g_free (pass); return; } //curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); for (i = 0; i < file_len; i++) { tmp = g_strdup_printf ("DELE %s", file[i]); comms = curl_slist_append (comms, tmp); g_free (tmp); } usrpas = g_strdup_printf ("%s:%s", user, pass); command = g_strdup_printf ("ftp://%s", host); g_printf ("---\nRemaining remotely:\n"); curl_easy_setopt (curl, CURLOPT_QUOTE, comms); curl_easy_setopt (curl, CURLOPT_FTPLISTONLY, 1); curl_easy_setopt (curl, CURLOPT_USERPWD, usrpas); curl_easy_setopt (curl, CURLOPT_URL, command); if (curl_easy_perform (curl)) g_message ("Remote deletion failed!"); curl_easy_cleanup (curl); g_free (host); g_free (user); g_free (pass); g_free (usrpas); g_free (command); curl_slist_free_all (comms); } gchar * top10_get_host () { gchar *tmp; gchar *host = NULL; if (keyfile == NULL) keyfile = g_key_file_new (); top10_keyfile_proverbaro (); host = g_key_file_get_string (keyfile, "proverbo", "kie", NULL); tmp = g_strconcat (_("No valid host"), ": ", _("nothing done"), ".", NULL); if (host == NULL) top10_message (tmp); else if (strlen (host) == 0) { top10_message (tmp); g_free (host); host = NULL; } g_free (tmp); return (host); } gchar * top10_get_user (gchar * updown) { gchar *tmp; gchar *user = NULL; gchar *host = NULL; if (keyfile == NULL) keyfile = g_key_file_new (); if (top10_keyfile_proverbaro () == FALSE) return (NULL); host = g_key_file_get_string (keyfile, "proverbo", "kie", NULL); if (g_str_equal (updown, "downuser")) user = g_strconcat ("klavaro@", host, NULL); else { tmp = g_key_file_get_string (keyfile, "proverbo", "kiu", NULL); user = g_strconcat (tmp, "@", host, NULL); g_free (tmp); } g_free (host); if (user == NULL) { tmp = g_strconcat (_("No valid user is defined"), ": ", _("nothing done"), ".", NULL); top10_message (tmp); g_free (tmp); return (NULL); } else if (strlen (user) == 0) { tmp = g_strconcat (_("No valid user is defined"), ": ", _("nothing done"), ".", NULL); top10_message (tmp); g_free (tmp); g_free (user); return (NULL); } return (user); } gchar * top10_get_pass (gchar * updown) { gsize i, j; gsize max; gchar *tmp; gchar *pass = NULL; time_t when; struct tm *ltime; when = time (NULL); ltime = localtime (&when); if (keyfile == NULL) keyfile = g_key_file_new (); if (g_str_equal (updown, "downpass")) { tmp = g_build_filename (main_path_user (), "adm.txt", NULL); if (! g_file_get_contents (tmp, &pass, NULL, NULL)) { g_free (tmp); g_free (pass); g_message ("You are not the administrator of Klavaro's default host. Nothing done"); return (NULL); } g_free (tmp); } else { if (top10_keyfile_proverbaro () == FALSE) return (NULL); tmp = g_key_file_get_string (keyfile, "proverbo", "kiel", NULL); pass = g_strdup (tmp); max = strlen (pass) - 1; for (i = 0, j = 0; i < max; i++) { tmp[j] = pass[i]; if (pass[i] == ' ') pass[i + 1] = g_ascii_toupper (pass[i + 1]); else j++; } tmp[j] = pass[i]; tmp[j + 1] = '\0'; g_free (pass); pass = g_strdup_printf ("%s%i", tmp, ltime->tm_year + 1900); g_free (tmp); } if (pass == NULL) { tmp = g_strconcat (_("No valid password is defined"), ": ", _("nothing done"), ".", NULL); top10_message (tmp); g_free (tmp); return (NULL); } if (strlen (pass) == 0) { tmp = g_strconcat (_("No valid password is defined"), ": ", _("nothing done"), ".", NULL); top10_message (tmp); g_free (tmp); g_free (pass); return (NULL); } return (pass); } gboolean top10_keyfile_proverbaro () { gchar *tmp; FILE *fh; CURL *curl; if (keyfile == NULL) keyfile = g_key_file_new (); tmp = g_build_filename (main_path_user (), "proverbaro.desktop", NULL); if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) { fh = g_fopen (tmp, "wb"); if (!fh) { g_message ("Not able to write to: %s", tmp); g_free (tmp); return FALSE; } if (! (curl = curl_easy_init ()) ) { g_message ("Not able to initialize 'curl'"); fclose (fh); g_free (tmp); return FALSE; } //curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); curl_easy_setopt (curl, CURLOPT_WRITEDATA, fh); curl_easy_setopt (curl, CURLOPT_URL, "http://klavaro.sourceforge.net/proverbaro.desktop"); if (curl_easy_perform (curl)) { top10_message (_("Not able to reach default host.")); curl_easy_cleanup (curl); fclose (fh); g_free (tmp); return FALSE; } curl_easy_cleanup (curl); fclose (fh); } g_key_file_load_from_file (keyfile, tmp, G_KEY_FILE_NONE, NULL); g_free (tmp); return TRUE; }