/* MultiSync - A PIM data synchronization program Copyright (C) 2002-2003 Bo Lincoln This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; In addition, as a special exception, Bo Lincoln gives permission to link the code of this program with the OpenSSL library (or with modified versions of OpenSSL that use the same license as OpenSSL), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ /* * $Id: gui.c,v 1.51 2004/03/04 19:08:17 lincoln Exp $ */ #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include "interface.h" #include "support.h" #include "syncengine.h" #include "gui.h" #include "sync_vtype.h" extern gboolean multisync_debug; extern GList *pluginlist; extern GList *syncpairlist; GtkWidget* mainwindow = NULL; GtkWidget* optionwindow = NULL; GtkWidget* pluginwindow = NULL; GtkWidget* logwindow = NULL; sync_pair *optionpair = NULL; extern char *datadir; sync_object_type activefiltertype; sync_direction activefilterdir; char *statusstring = NULL; // UNIX socket for inter-MultiSync-communication int procsockfd = -1; int procsockstreamtag = -1; char procsockbuf[256]; int procsockpos = 0; gpointer (*plugin_function)(); #define CALL_PLUGIN_ASYNC(mod, name, args) ((plugin_function=dlsym(mod->plugin,name))?(*plugin_function)args:sync_set_requestfailed(thissync)) #define CALL_PLUGIN(mod, name, args) ((plugin_function=dlsym(mod->plugin,name))?(*plugin_function)args:NULL) #define CHECK_PLUGIN(mod, name) (dlsym(mod->plugin,name)) sync_pair *get_selected_pair(void) { GtkTreeSelection *select; GtkTreeIter iter; GtkTreeModel *model; sync_pair *pair = NULL; select = gtk_tree_view_get_selection (GTK_TREE_VIEW(lookup_widget(mainwindow, "syncpairlist"))); if (gtk_tree_selection_get_selected (select, &model, &iter)) { gtk_tree_model_get (model, &iter, 2, &pair, -1); } return(pair); } void show_pairlist() { GtkListStore* pairlist; GtkTreeSelection *select; char *columns[] = {NULL, NULL, NULL, NULL}; int n; gboolean nonempty = (g_list_length(syncpairlist) > 0); pairlist = g_object_get_data(G_OBJECT(mainwindow), "syncpairstore"); gtk_widget_set_sensitive(lookup_widget(mainwindow, "editbutton"), nonempty); gtk_widget_set_sensitive(lookup_widget(mainwindow, "deletebutton"), nonempty); gtk_widget_set_sensitive(lookup_widget(mainwindow, "logbutton"), nonempty); gtk_widget_set_sensitive(lookup_widget(mainwindow, "syncnowbutton"), nonempty); gtk_list_store_clear(pairlist); select = gtk_tree_view_get_selection (GTK_TREE_VIEW(lookup_widget(mainwindow, "syncpairlist"))); for (n = 0; n < g_list_length(syncpairlist); n++) { GtkTreeIter iter; sync_pair *pair = g_list_nth_data(syncpairlist, n); columns[0] = sync_pair_to_string(pair); if (pair->status) columns[1] = pair->status; else columns[1] = ""; gtk_list_store_append (pairlist, &iter); gtk_list_store_set(pairlist, &iter, 0, columns[0], 1, columns[1], 2, pair, 3, !pair->manualonly, -1); if (n == 0) gtk_tree_selection_select_iter(select, &iter); g_free(columns[0]); } } typedef struct { sync_pair *pair; gboolean realaction; } set_pairlist_status_args; gboolean do_set_pairlist_status(gpointer data) { set_pairlist_status_args *arg = data; int n; GtkListStore* pairlist; if (mainwindow) { if ((pairlist = g_object_get_data(G_OBJECT(mainwindow), "syncpairstore"))) { for (n = 0; n < g_list_length(syncpairlist); n++) { if (g_list_nth_data(syncpairlist,n) == arg->pair) { GtkTreeIter iter; gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(pairlist), &iter, NULL, n); gtk_list_store_set(pairlist, &iter, 1, arg->pair->status, -1); } } } if (arg->realaction) gtk_window_set_title(GTK_WINDOW(mainwindow), arg->pair->status); else gtk_window_set_title(GTK_WINDOW(mainwindow), "MultiSync"); } g_free(arg); return(FALSE); } void async_set_pairlist_status(sync_pair *pair, char *status, gboolean realaction) { if (pair->status) g_free(pair->status); pair->status = g_strdup(status); if (mainwindow) { set_pairlist_status_args *arg = g_malloc(sizeof(set_pairlist_status_args)); g_assert(arg); arg->pair = pair; arg->realaction = realaction; g_idle_add(do_set_pairlist_status, arg); } } // Public plugin API function void sync_set_pair_status(sync_pair *pair, char *status) { if (pair) async_set_pairlist_status(pair, status, FALSE); } typedef struct { sync_pair *pair; char *logstring; sync_log_type type; } add_pairlist_log_args; gboolean do_add_pairlist_log(gpointer data) { add_pairlist_log_args *arg = data; GList *last = g_list_last(arg->pair->log); gboolean done = FALSE; if (last) { sync_pair_log *log = last->data; if (log && log->logstring && !strcmp(log->logstring, arg->logstring)) { // Same as last time, replace g_free(log->logstring); log->logstring = arg->logstring; time(&log->timestamp); log->type = arg->type; log->repeat++; done = TRUE; } } if (!done) { // Append new string sync_pair_log *log = g_malloc0(sizeof(sync_pair_log)); log->logstring = arg->logstring; time(&log->timestamp); log->type = arg->type; arg->pair->log = g_list_append(arg->pair->log, log); if (g_list_length(arg->pair->log) > 50) { // Shorten the list if too long. GList *first = g_list_first(arg->pair->log); sync_pair_log *log = first->data; if (log->logstring) g_free(log->logstring); g_free(log); arg->pair->log = g_list_remove(arg->pair->log, log); } } logwindow_show_log(); g_free(arg); return(FALSE); } void async_add_pairlist_log(sync_pair *pair, char* logstring, sync_log_type type) { add_pairlist_log_args *arg = g_malloc(sizeof(add_pairlist_log_args)); g_assert(arg); arg->pair = pair; arg->logstring = g_strdup(logstring); arg->type = type; g_idle_add(do_add_pairlist_log, arg); } void clear_pairlist_log(void) { sync_pair *pair = NULL; if (!logwindow || !get_selected_pair() ) return; pair = get_selected_pair(); while (pair->log) { GList *first = g_list_first(pair->log); sync_pair_log *log = first->data; if (log->logstring) g_free(log->logstring); g_free(log); pair->log = g_list_remove(pair->log, log); } logwindow_show_log(); } void logwindow_show_log(void) { GtkListStore *loglist; sync_pair *pair = NULL; int len; int n; char *wintitle; GdkVisual *visual; GdkColormap *colormap; GdkColor green, red; if (!logwindow || !get_selected_pair()) return; pair = get_selected_pair(); wintitle = g_strdup_printf("%s - %s log", pair->localclient->longname? pair->localclient->longname: pair->localclient->shortname, pair->remoteclient->longname? pair->remoteclient->longname: pair->remoteclient->shortname); gtk_window_set_title(GTK_WINDOW(logwindow), wintitle); g_free(wintitle); len = g_list_length(pair->log); loglist = g_object_get_data(G_OBJECT(logwindow), "logstore"); gtk_list_store_clear(loglist); visual = gdk_visual_get_system(); colormap = gdk_colormap_new(visual, FALSE); gdk_color_parse("green", &green); gdk_color_parse("red", &red); gdk_colormap_alloc_color (colormap, &green, FALSE, TRUE); gdk_colormap_alloc_color (colormap, &red, FALSE, TRUE); for (n = 0; n < len; n++) { GtkTreeIter iter; char *columns[3] = { NULL, NULL, NULL }; char *d, *l; sync_pair_log *log = g_list_nth_data(pair->log, n); d = g_strdup(ctime(&log->timestamp)); if (strlen(d) > 0 && d[strlen(d)-1] == '\n') d[strlen(d)-1] = 0; // Remove stupid newline columns[0] = d; if (log->repeat > 0) l = g_strdup_printf("%s (repeated %d times)", log->logstring, log->repeat+1); else l = g_strdup(log->logstring); columns[1] = l; gtk_list_store_append (loglist, &iter); gtk_list_store_set(loglist, &iter, 0, columns[0], 1, columns[1], -1); g_free(d); g_free(l); /*if (log->type == SYNC_LOG_SUCCESS) gtk_list_store_set_foreground(loglist, n, &green); else gtk_list_store_set_foreground(loglist, n, &red);*/ } gdk_colormap_free_colors(colormap, &green, 1); gdk_colormap_free_colors(colormap, &red, 1); } void open_logwindow(void) { if (!logwindow) { GtkListStore *loglist = gtk_list_store_new(2,G_TYPE_STRING, G_TYPE_STRING); GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); GtkTreeViewColumn *column; GtkTreeView *logtreeview; logwindow = create_logwindow(); logtreeview = GTK_TREE_VIEW(lookup_widget(logwindow, "logtreeview")); gtk_tree_view_set_model(logtreeview, GTK_TREE_MODEL(loglist)); g_object_set_data(G_OBJECT(logwindow), "logstore", loglist); column = gtk_tree_view_column_new_with_attributes("Time", renderer, "text", 0, NULL); gtk_tree_view_column_set_min_width(column, 100); gtk_tree_view_column_set_reorderable (column, TRUE); gtk_tree_view_column_set_clickable (column, TRUE); gtk_tree_view_append_column (logtreeview, column); column = gtk_tree_view_column_new_with_attributes("Log", renderer, "text", 1, NULL); gtk_tree_view_column_set_min_width(column, 300); gtk_tree_view_column_set_clickable (column, TRUE); gtk_tree_view_column_set_reorderable (column, TRUE); gtk_tree_view_append_column (logtreeview, column); gtk_widget_show(logwindow); } logwindow_show_log(); } void close_logwindow(void) { if (logwindow) { gtk_widget_destroy(logwindow); logwindow = NULL; } } gboolean sync_set_multisync_status(gpointer data) { if (mainwindow) { gnome_appbar_push(GNOME_APPBAR(lookup_widget(mainwindow, "appbar")), statusstring); } return(FALSE); } void async_set_multisync_status(char *status) { if (status) { if (statusstring) g_free(statusstring); statusstring = g_strdup(status); } gtk_idle_add(sync_set_multisync_status, NULL); } void mainwindow_save_size(void) { if (mainwindow) { GConfClient *gconf = gconf_client_get_default (); int w, h; gtk_window_get_size(GTK_WINDOW(mainwindow), &w, &h); gconf_client_set_int(gconf, SYNC_GCONF_PATH"/main_width", w, NULL); gconf_client_set_int(gconf, SYNC_GCONF_PATH"/main_height", h, NULL); g_object_unref(gconf); } } void sync_pair_auto_toggled(GtkCellRendererToggle *cellrenderertoggle, gchar *path, gpointer user_data) { GtkTreeSelection *select; GtkTreeIter iter; GtkTreeModel *model; sync_pair *pair = NULL; gboolean autosync = FALSE; GtkListStore *pairlist = user_data; if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(pairlist), &iter, path)) { gtk_tree_model_get (GTK_TREE_MODEL(pairlist), &iter, 2, &pair, 3, &autosync, -1); autosync = !autosync; pair->manualonly = !autosync; gtk_list_store_set(pairlist, &iter, 3, autosync, -1); save_syncpair(pair); sync_settings_changed(pair); // Tell the thread that we have changed } } static void sync_resync_gconf_notify (GConfClient *gconf, guint cnxn_id, GConfEntry *entry, gpointer user_data) { GConfValue *value; gboolean checked; if (entry && !strcmp(gconf_entry_get_key(entry), SYNC_GCONF_PATH"/showresync")) { value = gconf_entry_get_value (entry); checked = gconf_value_get_bool (value); if (checked) gtk_widget_show(lookup_widget(mainwindow, "resyncnowbutton")); else gtk_widget_hide(lookup_widget(mainwindow, "resyncnowbutton")); } } gboolean open_mainwindow(gpointer data) { char *filename; GConfClient *gconf = gconf_client_get_default (); GtkCheckMenuItem *menuitem; GError* err = NULL; gboolean notray, nogui, showresync; int w,h; GtkListStore *pairlist = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER,G_TYPE_BOOLEAN); GtkTreeView *syncpairlist; GtkTreeSelection *select; GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); GtkCellRenderer *boolrenderer = gtk_cell_renderer_toggle_new(); GtkTreeViewColumn *column; mainwindow = create_mainwindow(); gnome_app_enable_layout_config(GNOME_APP(mainwindow), TRUE); gconf_client_notify_add (gconf, SYNC_GCONF_PATH"/showresync", sync_resync_gconf_notify, NULL, NULL, NULL); syncpairlist = GTK_TREE_VIEW(lookup_widget(mainwindow, "syncpairlist")); gtk_tree_view_set_model(syncpairlist, GTK_TREE_MODEL(pairlist)); g_object_set_data(G_OBJECT(mainwindow), "syncpairstore", pairlist); g_signal_connect (G_OBJECT (boolrenderer), "toggled", G_CALLBACK (sync_pair_auto_toggled), pairlist); column = gtk_tree_view_column_new_with_attributes("Auto", boolrenderer, "active", 3, NULL); gtk_tree_view_column_set_min_width(column, 20); gtk_tree_view_append_column (syncpairlist, column); column = gtk_tree_view_column_new_with_attributes("Synchronization pair", renderer, "text", 0, NULL); gtk_tree_view_column_set_min_width(column, 200); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_append_column (syncpairlist, column); column = gtk_tree_view_column_new_with_attributes("Status", renderer, "text", 1, NULL); gtk_tree_view_column_set_min_width(column, 150); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_append_column (syncpairlist, column); select = gtk_tree_view_get_selection (GTK_TREE_VIEW (syncpairlist)); gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE); g_signal_connect (G_OBJECT (select), "changed", G_CALLBACK (sync_pair_selected), NULL); w = gconf_client_get_int(gconf, SYNC_GCONF_PATH"/main_width", NULL); if (w <= 0) w = 300; h = gconf_client_get_int(gconf, SYNC_GCONF_PATH"/main_height", NULL); if (h <= 0) h = 150; gtk_window_resize(GTK_WINDOW(mainwindow), w, h); gtk_widget_show (mainwindow); filename = g_strdup_printf("%s/%s", PACKAGE_DATA_DIR, "pixmaps/multisync.png"); gnome_window_icon_set_from_file(GTK_WINDOW(mainwindow), filename); g_free(filename); show_pairlist(); sync_set_multisync_status(NULL); menuitem = GTK_CHECK_MENU_ITEM(lookup_widget(mainwindow, "showtrayitem")); notray = gconf_client_get_bool (gconf, SYNC_GCONF_PATH"/no_tray_icon", NULL); gtk_check_menu_item_set_active(menuitem, !notray); menuitem = GTK_CHECK_MENU_ITEM(lookup_widget(mainwindow, "starthiddenitem")); nogui = gconf_client_get_bool (gconf, SYNC_GCONF_PATH"/no_gui", NULL); gtk_check_menu_item_set_active(menuitem, nogui); menuitem = GTK_CHECK_MENU_ITEM(lookup_widget(mainwindow, "showresyncitem")); showresync = gconf_client_get_bool (gconf, SYNC_GCONF_PATH"/showresync", NULL); gtk_check_menu_item_set_active(menuitem, showresync); if (showresync) gtk_widget_show(lookup_widget(mainwindow, "resyncnowbutton")); else gtk_widget_hide(lookup_widget(mainwindow, "resyncnowbutton")); g_object_unref(gconf); return(FALSE); } void show_common_object_types(sync_plugin *loc, sync_plugin *rem) { sync_object_type objtype; objtype = SYNC_OBJECT_TYPE_ANY; if (loc) objtype &= (sync_object_type) CALL_PLUGIN(loc, "object_types", ()); if (rem) objtype &= (sync_object_type) CALL_PLUGIN(rem, "object_types", ()); optionpair->object_types &= objtype; if (objtype & SYNC_OBJECT_TYPE_CALENDAR) { gtk_widget_show(lookup_widget(optionwindow, "calendarcheck")); if (optionpair->object_types & SYNC_OBJECT_TYPE_CALENDAR) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow,"calendarcheck")), 1); } else gtk_widget_hide(lookup_widget(optionwindow, "calendarcheck")); if (objtype & SYNC_OBJECT_TYPE_PHONEBOOK) { gtk_widget_show(lookup_widget(optionwindow, "addressbookcheck")); if (optionpair->object_types & SYNC_OBJECT_TYPE_PHONEBOOK) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow,"addressbookcheck")), 1); } else gtk_widget_hide(lookup_widget(optionwindow, "addressbookcheck")); if (objtype & SYNC_OBJECT_TYPE_TODO) { gtk_widget_show(lookup_widget(optionwindow, "todocheck")); if (optionpair->object_types & SYNC_OBJECT_TYPE_TODO) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow,"todocheck")), 1); } else gtk_widget_hide(lookup_widget(optionwindow, "todocheck")); if (!objtype) gtk_widget_show(lookup_widget(optionwindow, "nocommontypelabel")); else gtk_widget_hide(lookup_widget(optionwindow, "nocommontypelabel")); } void localoption_selected(GtkMenuItem *menuitem, gpointer user_data) { sync_plugin *plugin; sync_pair *pair; GtkButton *localedit; char *info; pair = optionpair; plugin = (sync_plugin*) gtk_object_get_data (GTK_OBJECT (menuitem), "plugin"); localedit = GTK_BUTTON(lookup_widget(optionwindow, "localedit")); pair->localclient = plugin; if (pair->localname) g_free(pair->localname); pair->localname = g_strdup(plugin->shortname); if (CHECK_PLUGIN(plugin,"open_option_window")) gtk_widget_set_sensitive(GTK_WIDGET(localedit), TRUE); else gtk_widget_set_sensitive(GTK_WIDGET(localedit), FALSE); show_common_object_types(pair->localclient, pair->remoteclient); info = CALL_PLUGIN(plugin, "plugin_info", ()); gtk_label_set_text(GTK_LABEL(lookup_widget(optionwindow, "localinfolabel")), info?info:"No information on the chosen plugin."); } void remoteoption_selected(GtkMenuItem *menuitem, gpointer user_data) { sync_plugin *plugin; sync_pair *pair; char *info; GtkButton *remoteedit; pair = optionpair; plugin = (sync_plugin*) gtk_object_get_data (GTK_OBJECT (menuitem), "plugin"); remoteedit = GTK_BUTTON(lookup_widget(optionwindow, "remoteedit")); pair->remoteclient = plugin; if (pair->remotename) g_free(pair->remotename); pair->remotename = g_strdup(plugin->shortname); if (CHECK_PLUGIN(plugin,"open_option_window")) gtk_widget_set_sensitive(GTK_WIDGET(remoteedit), TRUE); else gtk_widget_set_sensitive(GTK_WIDGET(remoteedit), FALSE); show_common_object_types(pair->localclient, pair->remoteclient); info = CALL_PLUGIN(plugin, "plugin_info", ()); gtk_label_set_text(GTK_LABEL(lookup_widget(optionwindow, "remoteinfolabel")), info?info:"No information on the chosen plugin."); } int syncintervals[] = { 10, 30, 60, 2*60, 5*60, 10*60, 30*60, 3600, 2*3600, 4*3600, 8*3600, 12*3600, 24*3600, 0, -1 }; int dwelltimes[] = { 0, 1, 2, 5, 10, 20, 30, 60, 2*60, -1 }; int reconnintervals[] = { 1, 2, 5, 10, 20, 30, 60, 2*60, 5*60, 10*60, 30*60, 3600, -1 }; char *interval_to_string(int interval) { char *ret = NULL; if (interval <= 60) ret = g_strdup_printf("%d secs", interval); else if (interval <= 3600) ret = g_strdup_printf("%d mins", interval/60); else if (interval <= 24*3600) ret = g_strdup_printf("%d hours", interval/3600); else ret = g_strdup_printf("%d days", interval/3600/24); return(ret); } int index_to_time(int* intervals, int index) { int t = 0; while (intervals[t]>=0 && t < index) t++; if (intervals[t]>=0) return(intervals[t]); return(intervals[t-1]); } int time_to_index(int* intervals, int secs) { int t = 0; while (intervals[t]>=0 && ((secs > 0 && intervals[t] < secs) || (secs == 0 && intervals[t] != secs))) t++; if (intervals[t]>=0) return(t); return(t-1); } void syncinterval_changed(GtkAdjustment *adjustment) { int val = (int) adjustment->value; GtkLabel *label; char *text; label = GTK_LABEL(gtk_object_get_data(GTK_OBJECT(optionwindow), "syncintervallabel")); optionpair->syncinterval = index_to_time(syncintervals, val); if (optionpair->syncinterval) text = interval_to_string(optionpair->syncinterval); else text = g_strdup("On change"); gtk_label_set_text(label, text); g_free(text); } void dwell_changed(GtkAdjustment *adjustment) { int val = (int) adjustment->value; GtkLabel *label; char *text; label = GTK_LABEL(gtk_object_get_data(GTK_OBJECT(optionwindow), "dwelllabel")); optionpair->dwelltime = index_to_time(dwelltimes, val); text = interval_to_string(optionpair->dwelltime); gtk_label_set_text(label, text); g_free(text); } void reconninterval_changed(GtkAdjustment *adjustment) { int val = (int) adjustment->value; GtkLabel *label; char *text; label = GTK_LABEL(gtk_object_get_data(GTK_OBJECT(optionwindow), "reconnintervallabel")); optionpair->reconninterval = index_to_time(reconnintervals, val); text = interval_to_string(optionpair->reconninterval); gtk_label_set_text(label, text); g_free(text); } void ok_syncpairwindow() { GtkWidget *button; if (pluginwindow) return; // Fetch data from the window optionpair->playsyncsound = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "syncsoundcheck"))); optionpair->playwelcomesound = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "welcomesoundcheck"))); if (optionpair->syncsound) g_free(optionpair->syncsound); optionpair->syncsound = g_strdup(gtk_entry_get_text(GTK_ENTRY(lookup_widget(optionwindow, "syncsoundentry")))); if (optionpair->welcomesound) g_free(optionpair->welcomesound); optionpair->welcomesound = g_strdup(gtk_entry_get_text(GTK_ENTRY(lookup_widget(optionwindow, "welcomesoundentry")))); if (optionpair->displayname) g_free(optionpair->displayname); optionpair->displayname = g_strdup(gtk_entry_get_text(GTK_ENTRY(lookup_widget(optionwindow, "displaynameentry")))); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatemanualradio")))) optionpair->duplicate_mode = SYNC_DUPLICATE_ACTION_NONE; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatefirstradio")))) optionpair->duplicate_mode = SYNC_DUPLICATE_ACTION_KEEPFIRST; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatesecondradio")))) optionpair->duplicate_mode = SYNC_DUPLICATE_ACTION_KEEPSECOND; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatebothradio")))) optionpair->duplicate_mode = SYNC_DUPLICATE_ACTION_KEEPBOTH; if (optionpair->original) { sync_pair *original = (sync_pair*) optionpair->original; apply_syncpair(original, optionpair); pthread_create(&original->syncthread, NULL, sync_main, original); } else { // New pair syncpairlist = g_list_append(syncpairlist, optionpair); pthread_create(&optionpair->syncthread, NULL, sync_main, optionpair); save_syncpair(optionpair); } gtk_widget_destroy(optionwindow); optionwindow = NULL; button = lookup_widget(mainwindow,"editbutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"newbutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"deletebutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"logbutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"syncnowbutton"); gtk_widget_set_sensitive(button, TRUE); show_pairlist(); } void cancel_syncpairwindow() { GtkWidget *button; if (pluginwindow) return; if (optionpair->original) { sync_pair *original = (sync_pair*) optionpair->original; if (!original->thread_running) pthread_create(&original->syncthread, NULL, sync_main, original); } free_syncpair(optionpair); gtk_widget_destroy(optionwindow); optionwindow = NULL; button = lookup_widget(mainwindow,"editbutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"newbutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"deletebutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"logbutton"); gtk_widget_set_sensitive(button, TRUE); button = lookup_widget(mainwindow,"syncnowbutton"); gtk_widget_set_sensitive(button, TRUE); } void sync_now() { GtkListStore* pairlist; int row; sync_pair *pair; pairlist = g_object_get_data(G_OBJECT(mainwindow), "syncpairstore"); pair = get_selected_pair(); if (pair) { sync_force_sync(pair); } } void resync_now() { GtkListStore* pairlist; int row; sync_pair *pair; pairlist = g_object_get_data(G_OBJECT(mainwindow), "syncpairstore"); pair = get_selected_pair(); if (pair) { if (sync_okcanceldialog("Are you sure you want to re-synchornize all entries?\nThis may take a long time and may potentially duplicate ALL of your entries.", TRUE)) sync_force_resync(pair); } } void do_delete_pair() { GtkListStore* pairlist; int row; sync_pair *pair; pairlist = g_object_get_data(G_OBJECT(mainwindow), "syncpairstore"); pair = get_selected_pair(); if (pair) { char *dirname; if (pair->thread_running) sync_quit(pair, NULL, NULL); pair->thread_running = FALSE; dirname = g_strdup_printf("%s/%s", pair->datapath, "syncpair"); unlink(dirname); g_free(dirname); syncpairlist = g_list_remove(syncpairlist, pair); show_pairlist(); } } void delete_pair() { if (sync_okcanceldialog("Are you sure you want to delete the selected pair?", TRUE)) do_delete_pair(); } void new_pair() { sync_pair *pair; struct stat sb; gboolean found = FALSE; int n = 1; char *dirname = NULL; pair = g_malloc0(sizeof(sync_pair)); // Generate a new directory name while (!found && n < 100) { dirname = g_strdup_printf("%s/%d", datadir, n); if (stat(dirname, &sb)) { if (!mkdir(dirname,S_IRWXU)) found = TRUE; } else { n++; g_free(dirname); } } if (n >= 100) { g_free(pair); return; } pair->datapath = dirname; pair->syncinterval = 3600; pair->dwelltime = 5; pair->reconninterval = 10; pair->object_types = 0xffff; pair->manualonly = TRUE; open_syncpairwindow(pair); } void open_syncpairwindow(sync_pair *pair) { GtkListStore* pairlist; if (optionwindow) return; pairlist = g_object_get_data(G_OBJECT(mainwindow), "syncpairstore"); if (!pair) { pair = get_selected_pair(); if (!pair) return; pair = clone_syncpair(pair); } // Turn off sync thread before editing if (pair->original && ((sync_pair *) pair->original)->thread_running) { async_set_pairlist_status((sync_pair *) pair->original, "Exiting...", 0); sync_quit((sync_pair *) pair->original, do_open_syncpairwindow, pair); ((sync_pair *) pair->original)->thread_running = FALSE; } else do_open_syncpairwindow(pair); } sync_filter *filter_find(sync_object_type type, sync_direction dir) { sync_filter *filter = NULL; int n; for (n = 0; !filter && n < g_list_length(optionpair->filters); n++) { sync_filter *f = g_list_nth_data(optionpair->filters, n); if (f->type == type && (f->dir&dir)) filter = f; } return(filter); } void filter_type_selected(GtkMenuItem *menuitem, gpointer user_data) { sync_object_type type = (sync_object_type) user_data; sync_filter *filter = NULL; activefiltertype = type; filter = filter_find(activefiltertype, activefilterdir); filter_show(filter); } void filter_rule_selected(GtkMenuItem *menuitem, gpointer user_data) { sync_rule rule = (sync_rule) user_data; sync_filter *filter = NULL; filter = filter_find(activefiltertype, activefilterdir); if (!filter) return; filter->rule = rule; gtk_widget_set_sensitive(lookup_widget(optionwindow, "filterfieldmenu"), rule!=SYNC_RULE_ALL && rule!=SYNC_RULE_NONE); gtk_widget_set_sensitive(lookup_widget(optionwindow, "filterdataentry"), rule!=SYNC_RULE_ALL && rule!=SYNC_RULE_NONE); } void filter_dir_selected(sync_direction dir) { sync_filter *filter = NULL; activefilterdir = dir; filter = filter_find(activefiltertype, activefilterdir); filter_show(filter); } void filter_show(sync_filter *filter) { GtkOptionMenu *om = GTK_OPTION_MENU(lookup_widget(optionwindow, "filterrulemenu")); if (!filter) return; switch (filter->rule) { case SYNC_RULE_ALL: gtk_option_menu_set_history(om, 0); break; case SYNC_RULE_ONLYIF: gtk_option_menu_set_history(om, 1); break; case SYNC_RULE_ALLBUT: gtk_option_menu_set_history(om, 2); break; case SYNC_RULE_NONE: gtk_option_menu_set_history(om, 3); break; } filter_rule_selected(NULL, (gpointer) filter->rule); gtk_entry_set_text(GTK_ENTRY(lookup_widget(optionwindow, "filterdataentry")), filter->data?filter->data:""); } void filter_data_changed(char *data) { sync_filter *filter = NULL; int n; for (n = 0; !filter && n < g_list_length(optionpair->filters); n++) { sync_filter *f = g_list_nth_data(optionpair->filters, n); if (f->type == activefiltertype && (f->dir&activefilterdir)) filter = f; } if (!filter) return; if (filter->data) g_free(filter->data); filter->data = g_strdup(data); } gboolean do_open_syncpairwindow(gpointer data) { GtkWidget *button; sync_pair *pair = data; if (pair->original) async_set_pairlist_status((sync_pair *) pair->original, "Editing options...", 0); button = lookup_widget(mainwindow,"editbutton"); gtk_widget_set_sensitive(button, FALSE); button = lookup_widget(mainwindow,"newbutton"); gtk_widget_set_sensitive(button, FALSE); button = lookup_widget(mainwindow,"deletebutton"); gtk_widget_set_sensitive(button, FALSE); button = lookup_widget(mainwindow,"logbutton"); gtk_widget_set_sensitive(button, FALSE); button = lookup_widget(mainwindow,"syncnowbutton"); gtk_widget_set_sensitive(button, FALSE); if (pair) { if (!optionwindow) { char *filename; int n; GtkMenu *localmenu, *remotemenu; GtkOptionMenu *localoption, *remoteoption; optionpair = pair; optionwindow = create_syncpairwin(); gtk_widget_show (optionwindow); filename = g_strdup_printf("%s/%s", PACKAGE_DATA_DIR, "pixmaps/multisync.png"); gnome_window_icon_set_from_file(GTK_WINDOW(optionwindow), filename); g_free(filename); localmenu = GTK_MENU(gtk_menu_new()); remotemenu = GTK_MENU(gtk_menu_new()); for (n = 0; n < g_list_length(pluginlist); n++) { sync_plugin* plugin = g_list_nth_data(pluginlist, n); GtkMenuItem *localmi, *remotemi; localmi = GTK_MENU_ITEM(gtk_menu_item_new_with_label(plugin->longname)); remotemi = GTK_MENU_ITEM(gtk_menu_item_new_with_label(plugin->longname)); gtk_signal_connect (GTK_OBJECT (localmi), "activate", GTK_SIGNAL_FUNC (localoption_selected), NULL); gtk_signal_connect (GTK_OBJECT (remotemi), "activate", GTK_SIGNAL_FUNC (remoteoption_selected), NULL); gtk_object_set_data (GTK_OBJECT (localmi), "plugin", plugin); gtk_object_set_data (GTK_OBJECT (remotemi), "plugin", plugin); gtk_menu_append(localmenu, GTK_WIDGET(localmi)); gtk_menu_append(remotemenu, GTK_WIDGET(remotemi)); if (plugin == pair->localclient || (!pair->localclient && !n)) { gtk_menu_set_active (localmenu, n); gtk_menu_item_activate(localmi); } if (plugin == pair->remoteclient || (!pair->remoteclient && !n)) { gtk_menu_set_active (remotemenu, n); gtk_menu_item_activate(remotemi); } } localoption = GTK_OPTION_MENU(gtk_object_get_data(GTK_OBJECT(optionwindow), "localoption")); remoteoption = GTK_OPTION_MENU(gtk_object_get_data(GTK_OBJECT(optionwindow), "remoteoption")); g_assert(localoption && remoteoption); gtk_widget_show_all(GTK_WIDGET(localmenu)); gtk_widget_show_all(GTK_WIDGET(remotemenu)); gtk_option_menu_set_menu(localoption, GTK_WIDGET(localmenu)); gtk_option_menu_set_menu(remoteoption, GTK_WIDGET(remotemenu)); { // Get the sync interval scale to work GtkAdjustment *syncintervaladj; GtkHScale *syncintervalscale; syncintervaladj = GTK_ADJUSTMENT(gtk_adjustment_new((float) time_to_index(syncintervals,pair->syncinterval), 0.0, 14.0, 1.0, 1.0, 1.0)); syncintervalscale = GTK_HSCALE(gtk_object_get_data(GTK_OBJECT(optionwindow), "syncintervalscale")); gtk_object_set_data(GTK_OBJECT(optionwindow), "syncintervaladj", syncintervaladj); gtk_object_set(GTK_OBJECT(syncintervalscale), "adjustment", syncintervaladj, NULL); gtk_signal_connect (GTK_OBJECT (syncintervaladj), "value-changed", GTK_SIGNAL_FUNC (syncinterval_changed), NULL); gtk_adjustment_value_changed(syncintervaladj); } { // Get the dwell time scale to work GtkAdjustment *dwelladj; GtkHScale *dwellscale; dwelladj = GTK_ADJUSTMENT(gtk_adjustment_new((float) time_to_index(dwelltimes,pair->dwelltime), 0.0, 9.0, 1.0, 1.0, 1.0)); dwellscale = GTK_HSCALE(gtk_object_get_data(GTK_OBJECT(optionwindow), "dwellscale")); gtk_object_set_data(GTK_OBJECT(optionwindow), "dwelladj", dwelladj); gtk_object_set(GTK_OBJECT(dwellscale), "adjustment", dwelladj, NULL); gtk_signal_connect (GTK_OBJECT (dwelladj), "value-changed", GTK_SIGNAL_FUNC (dwell_changed), NULL); gtk_adjustment_value_changed(dwelladj); } { // Get the reconn interval scale to work GtkAdjustment *reconnintervaladj; GtkHScale *reconnintervalscale; reconnintervaladj = GTK_ADJUSTMENT(gtk_adjustment_new((float) time_to_index(reconnintervals,pair->reconninterval), 0.0, 12.0, 1.0, 1.0, 1.0)); reconnintervalscale = GTK_HSCALE(gtk_object_get_data(GTK_OBJECT(optionwindow), "reconnintervalscale")); gtk_object_set_data(GTK_OBJECT(optionwindow), "reconnintervaladj", reconnintervaladj); gtk_object_set(GTK_OBJECT(reconnintervalscale), "adjustment", reconnintervaladj, NULL); gtk_signal_connect (GTK_OBJECT (reconnintervaladj), "value-changed", GTK_SIGNAL_FUNC (reconninterval_changed), NULL); gtk_adjustment_value_changed(reconnintervaladj); } // Set the sound options gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow,"syncsoundcheck")), optionpair->playsyncsound); if (optionpair->syncsound) gtk_entry_set_text(GTK_ENTRY(lookup_widget(optionwindow, "syncsoundentry")), optionpair->syncsound); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow,"welcomesoundcheck")), optionpair->playwelcomesound); if (optionpair->welcomesound) gtk_entry_set_text(GTK_ENTRY(lookup_widget(optionwindow, "welcomesoundentry")), optionpair->welcomesound); if (optionpair->displayname) gtk_entry_set_text(GTK_ENTRY(lookup_widget(optionwindow, "displaynameentry")), optionpair->displayname); if (optionpair->duplicate_mode == SYNC_DUPLICATE_ACTION_NONE) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatemanualradio")), TRUE); if (optionpair->duplicate_mode == SYNC_DUPLICATE_ACTION_KEEPFIRST) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatefirstradio")), TRUE); if (optionpair->duplicate_mode == SYNC_DUPLICATE_ACTION_KEEPSECOND) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatesecondradio")), TRUE); if (optionpair->duplicate_mode == SYNC_DUPLICATE_ACTION_KEEPBOTH) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(optionwindow, "duplicatebothradio")), TRUE); // Set the filter options { int i; GtkMenu *menu; GtkMenuItem *mi; // Create one filter per type if they don't exist menu = GTK_MENU(gtk_menu_new()); for (i = 0; i < 3; i++) { int k = 0; sync_object_type type = (i==0?SYNC_OBJECT_TYPE_CALENDAR: (i==1?SYNC_OBJECT_TYPE_PHONEBOOK: (i==2?SYNC_OBJECT_TYPE_TODO:0))); for (k = 0; k < 2; k++) { sync_direction dir = (k?SYNC_DIR_REMOTETOLOCAL: SYNC_DIR_LOCALTOREMOTE); gboolean found = FALSE; for (n = 0; !found && nfilters); n++) { sync_filter *filter = g_list_nth_data(optionpair->filters, n); if (filter->type == type && (filter->dir & dir)) { found = TRUE; if (filter->dir != dir) { // If two-way filter, split into two filters sync_filter *filter2 = g_malloc0(sizeof(sync_filter)); filter->dir = SYNC_DIR_LOCALTOREMOTE; filter2->dir = SYNC_DIR_REMOTETOLOCAL; filter2->type = filter->type; filter2->rule = filter->rule; if (filter->field) filter2->field = g_strdup(filter->field); filter2->data = g_strdup(filter->data); optionpair->filters = g_list_append(optionpair->filters, filter2); } } } if (!found) { sync_filter *filter = g_malloc0(sizeof(sync_filter)); filter->dir = dir; filter->type = type; filter->rule = SYNC_RULE_ALL; filter->field = g_strdup("CATEGORIES"); filter->data = g_strdup(""); optionpair->filters = g_list_append(optionpair->filters, filter); } } mi = GTK_MENU_ITEM(gtk_menu_item_new_with_label(sync_objtype_as_string(type))); gtk_signal_connect (GTK_OBJECT (mi), "activate", GTK_SIGNAL_FUNC (filter_type_selected), (gpointer) type); gtk_menu_append(menu, GTK_WIDGET(mi)); if (i == 0) { gtk_menu_set_active (localmenu, i); gtk_menu_item_activate(mi); } } activefilterdir = SYNC_DIR_LOCALTOREMOTE; activefiltertype = SYNC_OBJECT_TYPE_CALENDAR; gtk_widget_show_all(GTK_WIDGET(menu)); gtk_option_menu_set_menu(GTK_OPTION_MENU(lookup_widget(optionwindow, "filtertypemenu")), GTK_WIDGET(menu)); menu = GTK_MENU(gtk_menu_new()); mi = GTK_MENU_ITEM(gtk_menu_item_new_with_label("Always synchronize")); gtk_signal_connect (GTK_OBJECT (mi), "activate", GTK_SIGNAL_FUNC (filter_rule_selected), (gpointer) SYNC_RULE_ALL); gtk_menu_append(menu, GTK_WIDGET(mi)); mi = GTK_MENU_ITEM(gtk_menu_item_new_with_label("Synchronize only if")); gtk_signal_connect (GTK_OBJECT (mi), "activate", GTK_SIGNAL_FUNC (filter_rule_selected), (gpointer) SYNC_RULE_ONLYIF); gtk_menu_append(menu, GTK_WIDGET(mi)); mi = GTK_MENU_ITEM(gtk_menu_item_new_with_label("Do not synchronize if")); gtk_signal_connect (GTK_OBJECT (mi), "activate", GTK_SIGNAL_FUNC (filter_rule_selected), (gpointer) SYNC_RULE_ALLBUT); gtk_menu_append(menu, GTK_WIDGET(mi)); mi = GTK_MENU_ITEM(gtk_menu_item_new_with_label("Never synchronize")); gtk_signal_connect (GTK_OBJECT (mi), "activate", GTK_SIGNAL_FUNC (filter_rule_selected), (gpointer) SYNC_RULE_NONE); gtk_menu_append(menu, GTK_WIDGET(mi)); gtk_widget_show_all(GTK_WIDGET(menu)); gtk_option_menu_set_menu(GTK_OPTION_MENU(lookup_widget(optionwindow, "filterrulemenu")), GTK_WIDGET(menu)); filter_show(filter_find(activefiltertype, activefilterdir)); } } } return(FALSE); } void open_localplugin_window() { sync_plugin *plugin = optionpair->localclient; if (!pluginwindow && plugin && CHECK_PLUGIN(plugin, "open_option_window")) { pluginwindow = CALL_PLUGIN(plugin, "open_option_window", (optionpair, CONNECTION_TYPE_LOCAL)); } } void open_remoteplugin_window() { sync_plugin *plugin = optionpair->remoteclient; if (!pluginwindow && plugin && CHECK_PLUGIN(plugin, "open_option_window")) { pluginwindow = CALL_PLUGIN(plugin, "open_option_window", (optionpair, CONNECTION_TYPE_REMOTE)); } } void sync_plugin_window_closed() { pluginwindow = NULL; } // Exit all threads nicely gboolean do_main_quit(gpointer data) { int n; char *sockname; for (n = 0; n < g_list_length(syncpairlist); n++) { sync_pair *pair = g_list_nth_data(syncpairlist, n); if (pair->thread_running) { pair->thread_running = FALSE; sync_quit(pair, do_main_quit, NULL); return(FALSE); } } sockname = g_strdup_printf("/tmp/multisync-%s", g_get_user_name()); if (procsockfd >= 0) { close(procsockfd); procsockfd = -1; } unlink(sockname); // Remove the socket g_free(sockname); exit(0); } // Quit in a nice way void main_quit(void) { int n; mainwindow_save_size(); for (n = 0; n < g_list_length(syncpairlist); n++) { sync_pair *pair = g_list_nth_data(syncpairlist, n); if (pair->thread_running) { pair->thread_running = FALSE; sync_quit(pair, do_main_quit, NULL); return; } } exit(0); } gboolean sync_okcanceldialog(char *text, gboolean okcancel) { GtkWidget *sync_message; int ret=0; if (okcancel) { sync_message = gnome_message_box_new(text, GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_CANCEL, GNOME_STOCK_BUTTON_OK, NULL); gtk_window_set_title (GTK_WINDOW (sync_message), "MultiSync Question"); } else { sync_message = gnome_message_box_new(text, GNOME_MESSAGE_BOX_INFO, GNOME_STOCK_BUTTON_OK, NULL); gtk_window_set_title (GTK_WINDOW (sync_message), "MultiSync Information"); } gtk_window_set_modal(GTK_WINDOW(sync_message), TRUE); gtk_widget_show(sync_message); ret=gnome_dialog_run_and_close(GNOME_DIALOG(sync_message)); return(ret == 1); } void sync_pair_selected(GtkTreeSelection *selection, gpointer data) { gtk_widget_set_sensitive(lookup_widget(mainwindow, "editbutton"), TRUE); gtk_widget_set_sensitive(lookup_widget(mainwindow, "deletebutton"), TRUE); gtk_widget_set_sensitive(lookup_widget(mainwindow, "syncnowbutton"), TRUE); logwindow_show_log(); } typedef struct { sync_pair *pair; changed_object *change; } sync_ask_dbfull_arg; gboolean sync_do_ask_dbfull(gpointer data) { char *msg; GtkWidget *sync_message; sync_ask_dbfull_arg *arg = data; int ret; msg = g_strdup_printf("The database for %ss is full.", sync_objtype_as_string(arg->change->object_type)); sync_message = gnome_message_box_new(msg, GNOME_MESSAGE_BOX_QUESTION, "Try again next time", "Ignore", NULL); gtk_window_set_title (GTK_WINDOW (sync_message), "MultiSync Question"); gtk_window_set_modal(GTK_WINDOW(sync_message), TRUE); gtk_widget_show(sync_message); ret=gnome_dialog_run(GNOME_DIALOG(sync_message)); sync_set_requestmsg(ret==0?SYNC_MSG_FALSE:SYNC_MSG_TRUE, arg->pair); return(FALSE); } void sync_ask_dbfull(changed_object *change, sync_pair *pair) { sync_ask_dbfull_arg *arg = g_malloc0(sizeof(sync_ask_dbfull_arg)); arg->change = change; arg->pair = pair; g_idle_add(sync_do_ask_dbfull, arg); } void sync_process_socket_stream(gpointer data, int fd, GdkInputCondition cond) { int ret; char *eol; gboolean closeit = FALSE; ret = read(fd, procsockbuf+procsockpos, 256-procsockpos); if (ret <= 0) closeit = TRUE; else procsockpos += ret; // Find end of line for (eol = procsockbuf; eol < procsockbuf+procsockpos && *eol != '\r' && *eol != 0 && *eol != '\n'; eol++); if (eol < procsockbuf+procsockpos) { *eol = 0; closeit = TRUE; if (!strcmp(procsockbuf, "SHOWGUI")) { sync_show_gui(); } } if (closeit) { close(fd); gdk_input_remove(procsockstreamtag); procsockpos = 0; } } void sync_process_socket_connection(gpointer data, int fd, GdkInputCondition cond) { // Someone connected to our process socket. int streamfd; struct sockaddr_un mysock; int socksize = sizeof(struct sockaddr_un); streamfd = accept(fd, (struct sockaddr*) &mysock, &socksize); if (streamfd >= 0) { fcntl(streamfd, F_SETFL, O_NONBLOCK); procsockstreamtag = gdk_input_add(streamfd, GDK_INPUT_READ, sync_process_socket_stream, NULL); } } // Returns true if we should continue executing (false if it found // another process) gboolean sync_open_process_socket() { struct sockaddr_un mysock; char *sockname = NULL; mysock.sun_family = AF_UNIX; sockname = g_strdup_printf("/tmp/multisync-%s", g_get_user_name()); strncpy(mysock.sun_path, sockname, 108); g_free(sockname); procsockfd = socket(PF_UNIX, SOCK_STREAM, 0); if (procsockfd < 0) return(TRUE); if (!connect(procsockfd, (struct sockaddr*) &mysock, sizeof(struct sockaddr_un))) { char cmd[] = "SHOWGUI"; if (write(procsockfd, cmd, strlen(cmd)+1) == strlen(cmd)+1) { // Successfully told the original MultiSync instance to show GUI. close(procsockfd); procsockfd = -1; return(FALSE); } } close(procsockfd); procsockfd = socket(PF_UNIX, SOCK_STREAM, 0); if (procsockfd < 0) return(TRUE); unlink(mysock.sun_path); if (!bind(procsockfd, (struct sockaddr*) &mysock, sizeof(struct sockaddr_un))) { listen(procsockfd, 0); gdk_input_add(procsockfd, GDK_INPUT_READ, sync_process_socket_connection, NULL); return(TRUE); } else { printf("Failed to bind process socket.\n"); } close(procsockfd); procsockfd = -1; return(TRUE); } void sync_show_gui() { if (!mainwindow) { gtk_idle_add(open_mainwindow, NULL); } } void sync_hide_gui() { mainwindow_save_size(); gtk_widget_destroy(mainwindow); mainwindow = NULL; } void sync_show_msg(char *msg) { GtkWidget *sync_message; sync_message = gnome_message_box_new(msg, GNOME_MESSAGE_BOX_INFO, GNOME_STOCK_BUTTON_OK, NULL); gtk_window_set_title (GTK_WINDOW (sync_message), "MultiSync"); gtk_window_set_modal(GTK_WINDOW(sync_message), TRUE); gtk_widget_show(sync_message); } gboolean sync_do_show_msg(gpointer msg) { sync_show_msg((char*) msg); g_free(msg); return(FALSE); } void sync_async_msg(char *msg) { g_idle_add(sync_do_show_msg, g_strdup(msg)); } typedef struct { sync_pair *pair; changed_object *firstobj; changed_object *secondobj; gboolean sameuid; } sync_ask_duplicate_arg; gboolean sync_do_ask_duplicate(gpointer data) { GtkWidget *dupwin; sync_ask_duplicate_arg *arg = data; GtkTextBuffer *buffer; char *objstring, *name, *tmp; dupwin = create_duplicatewin(); gtk_object_set_data(GTK_OBJECT(dupwin), "syncpair", arg->pair); if (arg->sameuid) gtk_label_set_label(GTK_LABEL(lookup_widget(dupwin, "reasonlabel")), "This entry has been modified on both sides, but the" " modifications are not the same.\n" "How should MultiSync proceed?"); else gtk_label_set_label(GTK_LABEL(lookup_widget(dupwin, "reasonlabel")), "The following two entries are similar but not " "exactly equal.\n" "How should MultiSync proceed?"); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(lookup_widget(dupwin, "firsttextview"))); objstring = sync_object_string(arg->firstobj); gtk_text_buffer_set_text(buffer, objstring, strlen(objstring)); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(lookup_widget(dupwin, "secondtextview"))); g_free(objstring); objstring = sync_object_string(arg->secondobj); gtk_text_buffer_set_text(buffer, objstring, strlen(objstring)); g_free(objstring); name = sync_pair_to_string(arg->pair); tmp = g_strdup_printf("%s", name); gtk_label_set_label(GTK_LABEL(lookup_widget(dupwin, "syncpairlabel")), tmp); g_free(tmp); g_free(name); if (arg->pair->localclient) { name = g_strdup_printf("Entry from %s (first plugin):", arg->pair->localclient->longname); gtk_label_set_label(GTK_LABEL(lookup_widget(dupwin, "firstlabel")), name); g_free(name); } if (arg->pair->remoteclient) { name = g_strdup_printf("Entry from %s (second plugin):", arg->pair->remoteclient->longname); gtk_label_set_label(GTK_LABEL(lookup_widget(dupwin, "secondlabel")), name); g_free(name); } gtk_widget_show(dupwin); g_free(arg); return(FALSE); } char* sync_pair_to_string(sync_pair *pair) { char *name; if (pair->displayname && strlen(pair->displayname) > 0) name = g_strdup(pair->displayname); else { char *l = NULL, *r = NULL; if (pair->localclient) l = pair->localclient->longname; else l = pair->localname; if (pair->remoteclient) r = pair->remoteclient->longname; else r = pair->remotename; name = g_strdup_printf("%s - %s", l, r); } return(name); } void sync_duplicate_actionselected(GtkWidget *window, sync_duplicate_action action) { sync_pair *pair; pair = gtk_object_get_data(GTK_OBJECT(window), "syncpair"); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(window, "remembercheckbutton")))) pair->default_duplicate_action = action; gtk_widget_destroy(window); sync_set_requestdata((gpointer) action, pair); } void sync_ask_duplicate(changed_object *firstobj, changed_object *secondobj, gboolean sameuid, sync_pair *pair) { sync_ask_duplicate_arg *arg = g_malloc0(sizeof(sync_ask_duplicate_arg)); arg->firstobj = firstobj; arg->secondobj = secondobj; arg->pair = pair; arg->sameuid = sameuid; g_idle_add(sync_do_ask_duplicate, arg); }