1 /*
2  *      XSitecopy, for managing remote web sites with a GNOME interface.
3  *      Copyright (C) 2000, Lee Mallabone <lee@fonicmonkey.net>
4  *
5  *      This program is free software; you can redistribute it and/or modify
6  *      it under the terms of the GNU General Public License as published by
7  *      the Free Software Foundation; either version 2 of the License, or
8  *      (at your option) any later version.
9  *
10  *      This program is distributed in the hope that it will be useful,
11  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *      GNU General Public License for more details.
14  *
15  *      You should have received a copy of the GNU General Public License
16  *      along with this program; if not, write to the Free Software
17  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  */
20 
21 #include <stdlib.h>
22 #include "operations.h"
23 
24 extern struct site *selected_site;
25 extern GtkWidget *error_log_list, *error_log_window;
26 
27 extern struct site *all_sites;
28 extern float uploaded_bytes, upload_total;
29 
30 /* For the 'main' upload window */
31 GtkWidget *upload_window, *main_progressbar, *job_progressbar, *error_button;
32 GtkWidget *status_label, *op_label, *file_label, *dir_label;
33 GtkWidget *begin_button, *close_button, *kill_button, *keep_going_button;
34 pthread_t update_thread_id = 0;
35 
36 volatile int in_critical_section = 0, want_abort = 0;
37 sigjmp_buf abort_buf;
38 
39 /* This sets up a signal handler and provides a wrapper around
40  * site_ transfer operations.
41  * It uses setjmp and longjmp to do backward error recovery.
42  * This allows the aborting of operations without having to
43  * destroy threads, which is A Good Thing, because all
44  * site_updates use the same (single) thread. :)
45  */
46 
47 
48 /* Signal handler */
handle_abort(int sig)49 void handle_abort( int sig ) {
50    if( in_critical_section ) {
51       /* Can't abort now, so remember we want to for later */
52       want_abort = 1;
53    } else {
54       do_abort();
55    }
56 }
57 
58 /* Actually abort the update */
do_abort(void)59 void do_abort(void) {
60     printf("performing longjmp...\n");
61     want_abort = 0;
62     siglongjmp( abort_buf, 1 );
63 }
64 
65 /* Enter critical section */
fe_disable_abort(struct site * site)66 void fe_disable_abort( struct site *site ) {
67   in_critical_section = 1;
68 }
69 
70 /* Leave critical section */
fe_enable_abort(struct site * site)71 void fe_enable_abort( struct site *site ) {
72   in_critical_section = 0;
73   /* Carry out the abort if we were aborted while in the
74    * critical section */
75   if( want_abort ) {
76      do_abort();
77   }
78 }
79 
my_abortable_transfer_wrapper(struct site * site,enum site_op operation)80 int my_abortable_transfer_wrapper(struct site *site,
81 				  enum site_op operation )
82 {
83    int ret;
84    signal( SIGUSR1, handle_abort );
85    if( !sigsetjmp( abort_buf, 1 ) ) {
86        /* Normal execution */
87        switch (operation)
88 	 {
89 	  case site_op_update:
90 	     ret = site_update(site);
91 	     break;
92 	  case site_op_fetch:
93 	     ret = site_fetch(site);
94 	     break;
95 #if 0 /* Can't happen in current code. */
96 	  case site_op_resync:
97 	     ret = site_synch(site);
98 	     break;
99 #endif
100 #ifndef NDEBUG
101 	  default:
102 	     fprintf(stderr, "my_abortable_transfer_wrapper: unknown operation %d.  Aborting.\n", operation);
103 	     abort();
104 #endif /* !NDEBUG */
105 	 }
106    } else {
107        /* The update was aborted */
108        ret = SITE_ABORTED;
109    }
110    signal( SIGUSR1, SIG_IGN );
111    return ret;
112 }
113 
114 
close_main_update_window(GtkButton * button,gpointer data)115 void close_main_update_window(GtkButton * button, gpointer data)
116 {
117     extern GtkWidget *connection_label;
118     gtk_window_set_modal(GTK_WINDOW(upload_window), FALSE);
119     gtk_widget_destroy(upload_window);
120     connection_label = NULL;
121     return;
122 }
123 
abort_site_update(GtkWidget * button,gpointer data)124 void abort_site_update(GtkWidget * button, gpointer data)
125 {
126     extern pthread_t update_tid;
127     gtk_label_set(GTK_LABEL(status_label), "Aborting...");
128     pthread_kill(update_tid, SIGUSR1);
129 }
130 
131 /* This is just a skel until the next release */
132 
update_all_thread(void * no_data)133 void *update_all_thread(void *no_data)
134 {
135     extern sem_t *update_all_semaphore;
136     pthread_detach(pthread_self());
137     NE_DEBUG(DEBUG_GNOME, "update_all_thread: detached.\n");
138 
139     for(;;)
140       {
141 	  struct site *working_site;
142 	  NE_DEBUG(DEBUG_GNOME, "update_all_thread: sleeping...\n");
143 	  /* sleep straight away */
144 	  sem_wait(update_all_semaphore);
145 
146 	  for (working_site = all_sites;
147 	       working_site;
148 	       working_site = working_site->next)
149 	    {
150 		int ret;
151 		ret =
152 		  my_abortable_transfer_wrapper(working_site, site_op_update);
153 		set_status_after_operation(ret, GTK_LABEL(status_label));
154 		if (ret == SITE_ABORTED)
155 		  break;
156 	    }
157       }
158 }
159 
160 
update_thread(void * no_data)161 void *update_thread(void *no_data)
162 {
163     int ret;
164     extern sem_t *update_semaphore;
165     extern gboolean site_keepgoing;
166 
167     pthread_detach(pthread_self());
168     NE_DEBUG(DEBUG_GNOME, "update_thread: detached.\n");
169 
170     for(;;)
171       {
172 	  NE_DEBUG(DEBUG_GNOME, "update_thread: sleeping...\n");
173 	  /* sleep straight away */
174 	  sem_wait(update_semaphore);
175 	  NE_DEBUG(DEBUG_GNOME, "update_thread: Okay, who woke me up!?\n");
176 
177 	  gdk_threads_enter();
178 	  gtk_widget_set_sensitive(begin_button, FALSE);
179 	  gtk_widget_set_sensitive(keep_going_button, FALSE);
180 
181 	  NE_DEBUG(DEBUG_GNOME, "update_thread: Acquired gtk+ lock\n");
182 
183 	  if (verifysite_gnome(selected_site)) {
184 	      close_main_update_window(NULL, NULL);
185 	      NE_DEBUG(DEBUG_GNOME, "update_thread: The site was wrong, skipping.\n");
186 	      continue;
187 	  }
188 
189 	  NE_DEBUG(DEBUG_GNOME, "update_thread: Verified site okay, updating...");
190 
191 	  /* Perform the actual update */
192 	  if (GTK_TOGGLE_BUTTON(keep_going_button)->active) {
193 	      site_keepgoing = TRUE;
194 	  } else {
195 	      site_keepgoing = FALSE;
196 	  }
197 	  gdk_threads_leave();
198 
199 
200 	  /* site_update blocks until finished */
201 	  NE_DEBUG(DEBUG_GNOME, "update_thread: Entering site_update.\n");
202 	  /* we might want to give this a 3rd argument sometime to allow
203 	   * updating of single files at a time */
204 	  /* This calls site_update with a wrapper to facilitate good
205 	   * abort behaviour */
206 	  ret = my_abortable_transfer_wrapper(selected_site, site_op_update);
207 	  NE_DEBUG(DEBUG_GNOME,
208 		"update_thread: site_update returned value of %d.\n", ret);
209 
210 	  gdk_threads_enter();
211 	  switch (ret) {
212 	   case SITE_CONNECT:
213 	      gtk_label_set(GTK_LABEL(status_label), "Unable to establish connection.");
214 	      gtk_label_set(GTK_LABEL(op_label), " ");
215 	      gtk_label_set(GTK_LABEL(file_label), " ");
216 	      gtk_label_set(GTK_LABEL(dir_label), " ");
217 	      break;
218 	   case SITE_AUTH:
219 	      gtk_label_set(GTK_LABEL(status_label), "Authentication with the remote server failed..");
220 	      gtk_label_set(GTK_LABEL(op_label), " ");
221 	      gtk_label_set(GTK_LABEL(file_label), " ");
222 	      gtk_label_set(GTK_LABEL(dir_label), " ");
223 	      break;
224 	   case SITE_ERRORS:
225 	      gtk_label_set(GTK_LABEL(status_label), "There was a problem with the file/directory transfer.");
226 	      gtk_label_set(GTK_LABEL(op_label), " ");
227 	      gtk_label_set(GTK_LABEL(file_label), " ");
228 	      gtk_label_set(GTK_LABEL(dir_label), " ");
229 	      site_write_stored_state(selected_site);
230 	      rescan_selected(1);
231 	      gtk_widget_set_sensitive(error_button, TRUE);
232 	      break;
233 	   case SITE_LOOKUP:
234 	      gtk_label_set(GTK_LABEL(status_label), "Unable to connect: Host name look-up failed.");
235 	      gtk_label_set(GTK_LABEL(op_label), " ");
236 	      gtk_label_set(GTK_LABEL(file_label), " ");
237 	      gtk_label_set(GTK_LABEL(dir_label), " ");
238 	      break;
239 	   case SITE_OK:
240 	      gtk_label_set(GTK_LABEL(status_label), "Update complete. (No errors)");
241 	      gtk_label_set(GTK_LABEL(op_label), " ");
242 	      gtk_label_set(GTK_LABEL(file_label), " ");
243 	      gtk_label_set(GTK_LABEL(dir_label), " ");
244 	      site_write_stored_state(selected_site);
245 	      rescan_selected(1);
246 	      break;
247 	   case SITE_FAILED:
248 	      gtk_label_set(GTK_LABEL(status_label), "Update failed. (Authentication problems)");
249 	      gtk_label_set(GTK_LABEL(op_label), " ");
250 	      gtk_label_set(GTK_LABEL(file_label), " ");
251 	      gtk_label_set(GTK_LABEL(dir_label), " ");
252 	      break;
253 	   case SITE_ABORTED:
254 	      gtk_label_set(GTK_LABEL(status_label), "Update was aborted.");
255 	      gtk_label_set(GTK_LABEL(op_label), " ");
256 	      gtk_label_set(GTK_LABEL(file_label), " ");
257 	      gtk_label_set(GTK_LABEL(dir_label), " ");
258 	      site_write_stored_state(selected_site);
259 	      /*rescan_selected(1);*/
260 	      break;
261 	   default:
262 	      gtk_label_set(GTK_LABEL(status_label), "Unexpected Update Return Value! Contact Maintainer.");
263 	      NE_DEBUG(DEBUG_GNOME, "ARG! site_update returned %d.\n", ret);
264 	      break;
265 	  }
266 	  NE_DEBUG(DEBUG_GNOME, "Dealt with site_update's return code. Changing sensitivities.\n");
267 	  gtk_widget_hide (kill_button);
268 	  gtk_widget_show (close_button);
269 	  gtk_widget_set_sensitive(close_button, TRUE);
270 	  gtk_window_set_modal(GTK_WINDOW(upload_window), FALSE);
271 	  gdk_threads_leave();
272 	  NE_DEBUG(DEBUG_GNOME, "update_thread: Reported update status okay, looping...\n");
273       }
274 }
275 
276 
start_main_update(GtkWidget * button,gpointer single_or_all)277 int start_main_update(GtkWidget *button, gpointer single_or_all)
278 {
279     extern sem_t *update_semaphore, *update_all_semaphore;
280 
281     gtk_widget_set_sensitive(begin_button, FALSE);
282 /*    gtk_widget_set_sensitive(close_button, FALSE);*/
283     gtk_window_set_modal(GTK_WINDOW(upload_window), TRUE);
284     gtk_widget_hide(close_button);
285     gnome_dialog_append_button_with_pixmap (GNOME_DIALOG (upload_window),
286 					    "Stop!", GNOME_STOCK_PIXMAP_STOP);
287     kill_button = g_list_last (GNOME_DIALOG (upload_window)->buttons)->data;
288     gtk_signal_connect (GTK_OBJECT(kill_button), "clicked",
289 			GTK_SIGNAL_FUNC(abort_site_update), NULL);
290     gtk_widget_show(kill_button);
291    if (strcmp((gchar *)single_or_all, "single") == 0) {
292       printf("updating single site.\n");
293       sem_post(update_semaphore);
294    } else if (strcmp((gchar *)single_or_all, "all") == 0) {
295       printf("Updating ALL sites that need it.\n");
296       sem_post(update_all_semaphore);
297    } else {
298       g_assert_not_reached();
299    }
300     return 1;
301 }
302 
main_update_please(GtkWidget * update_button,gpointer data)303 int main_update_please(GtkWidget * update_button, gpointer data)
304 {
305     extern GtkWidget *connection_label;
306     GtkWidget *dialog_vbox1;
307     GtkWidget *vbox1;
308     GtkWidget *hseparator3;
309     GtkWidget *table1;
310     GtkWidget *label3;
311     GtkWidget *label6;
312     GtkWidget *hseparator1;
313     GtkWidget *label2;
314     GtkWidget *label1;
315     GtkWidget *dialog_action_area1;
316 
317     uploaded_bytes = 0.0;
318 
319     if (selected_site == NULL) {
320 	gnome_error_dialog("You must select a site if you want to upload the changes!");
321 	return 0;
322     }
323     if (!selected_site->remote_is_different) {
324 	gfe_status("Remote and local sites are already synchronised.");
325 	return 1;
326     }
327 
328     upload_total = selected_site->totalnew + selected_site->totalchanged;
329     make_error_window();
330     upload_window = gnome_dialog_new("Update Progress", NULL);
331     gtk_widget_set_usize(upload_window, 480, -2);
332 
333     dialog_vbox1 = GNOME_DIALOG(upload_window)->vbox;
334     gtk_widget_show(dialog_vbox1);
335 
336     vbox1 = gtk_vbox_new(FALSE, 1);
337     gtk_widget_ref(vbox1);
338     gtk_widget_show(vbox1);
339     gtk_box_pack_start(GTK_BOX(dialog_vbox1), vbox1, TRUE, TRUE, 0);
340 
341     hseparator3 = gtk_hseparator_new();
342     gtk_widget_ref(hseparator3);
343     gtk_widget_show(hseparator3);
344     gtk_box_pack_start(GTK_BOX(vbox1), hseparator3, TRUE, TRUE, 3);
345 
346     table1 = gtk_table_new(4, 2, FALSE);
347     gtk_widget_show(table1);
348     gtk_box_pack_start(GTK_BOX(vbox1), table1, TRUE, TRUE, 0);
349     gtk_table_set_row_spacings(GTK_TABLE(table1), 1);
350     gtk_table_set_col_spacings(GTK_TABLE(table1), 2);
351 
352     status_label = gtk_label_new("Click Upload to begin.");
353     gtk_widget_show(status_label);
354     connection_label = status_label;
355     gtk_table_attach(GTK_TABLE(table1), status_label, 1, 2, 0, 1,
356 		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
357 		     (GtkAttachOptions) (0), 0, 0);
358     gtk_label_set_justify(GTK_LABEL(status_label), GTK_JUSTIFY_LEFT);
359     gtk_misc_set_alignment(GTK_MISC(status_label), 7.45058e-09, 0.5);
360 
361     op_label = gtk_label_new(" ");
362     gtk_widget_show(op_label);
363     gtk_table_attach(GTK_TABLE(table1), op_label, 0, 2, 1, 2,
364 		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
365 		     (GtkAttachOptions) (0), 0, 0);
366     gtk_label_set_justify(GTK_LABEL(op_label), GTK_JUSTIFY_LEFT);
367     gtk_misc_set_alignment(GTK_MISC(op_label), 7.45058e-09, 0.5);
368 
369     file_label = gtk_label_new("");
370     gtk_widget_show(file_label);
371     gtk_table_attach(GTK_TABLE(table1), file_label, 0, 2, 2, 3,
372 		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
373 		     (GtkAttachOptions) (0), 0, 0);
374     gtk_label_set_justify(GTK_LABEL(file_label), GTK_JUSTIFY_LEFT);
375     gtk_misc_set_alignment(GTK_MISC(file_label), 7.45058e-09, 0.5);
376 
377     label3 = gtk_label_new("Status: ");
378     gtk_widget_show(label3);
379     gtk_table_attach(GTK_TABLE(table1), label3, 0, 1, 0, 1,
380 		     (GtkAttachOptions) (GTK_FILL),
381 		     (GtkAttachOptions) (0), 0, 0);
382     gtk_label_set_justify(GTK_LABEL(label3), GTK_JUSTIFY_LEFT);
383     gtk_misc_set_alignment(GTK_MISC(label3), 7.45058e-09, 0.5);
384 
385     label6 = gtk_label_new("To: ");
386     gtk_widget_show(label6);
387     gtk_table_attach(GTK_TABLE(table1), label6, 0, 1, 3, 4,
388 		     (GtkAttachOptions) (GTK_FILL),
389 		     (GtkAttachOptions) (0), 0, 0);
390     gtk_label_set_justify(GTK_LABEL(label6), GTK_JUSTIFY_LEFT);
391     gtk_misc_set_alignment(GTK_MISC(label6), 7.45058e-09, 0.5);
392 
393     dir_label = gtk_label_new(" ");
394     gtk_widget_show(dir_label);
395     gtk_table_attach(GTK_TABLE(table1), dir_label, 1, 2, 3, 4,
396 		     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
397 		     (GtkAttachOptions) (0), 0, 0);
398     gtk_label_set_justify(GTK_LABEL(dir_label), GTK_JUSTIFY_LEFT);
399     gtk_misc_set_alignment(GTK_MISC(dir_label), 7.45058e-09, 0.5);
400 
401     hseparator1 = gtk_hseparator_new();
402     gtk_widget_show(hseparator1);
403     gtk_box_pack_start(GTK_BOX(vbox1), hseparator1, TRUE, TRUE, 5);
404 
405     label2 = gtk_label_new("Current Progress");
406     gtk_widget_show(label2);
407     gtk_box_pack_start(GTK_BOX(vbox1), label2, TRUE, FALSE, 2);
408     gtk_misc_set_alignment(GTK_MISC(label2), 0.5, 1);
409 
410     main_progressbar = gtk_progress_bar_new();
411     gtk_widget_show(main_progressbar);
412     gtk_box_pack_start(GTK_BOX(vbox1), main_progressbar, TRUE, FALSE, 0);
413     gtk_progress_set_show_text(GTK_PROGRESS(main_progressbar), TRUE);
414 
415     label1 = gtk_label_new("Total Progress");
416     gtk_widget_show(label1);
417     gtk_box_pack_start(GTK_BOX(vbox1), label1, TRUE, FALSE, 2);
418     gtk_misc_set_alignment(GTK_MISC(label1), 0.5, 1);
419 
420     job_progressbar = gtk_progress_bar_new();
421     gtk_widget_show(job_progressbar);
422     gtk_box_pack_start(GTK_BOX(vbox1), job_progressbar, TRUE, FALSE, 0);
423     gtk_progress_set_show_text(GTK_PROGRESS(job_progressbar), TRUE);
424 
425     keep_going_button = gtk_check_button_new_with_label("Ignore any errors and always keep going.");
426     gtk_widget_show(keep_going_button);
427     gtk_box_pack_start(GTK_BOX(vbox1), keep_going_button, TRUE, TRUE, 0);
428 
429     dialog_action_area1 = GNOME_DIALOG(upload_window)->action_area;
430     gtk_widget_show(dialog_action_area1);
431     gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area1), GTK_BUTTONBOX_END);
432     gtk_button_box_set_spacing(GTK_BUTTON_BOX(dialog_action_area1), 8);
433 
434     gnome_dialog_append_button_with_pixmap(GNOME_DIALOG(upload_window),
435 				   "Upload", GNOME_STOCK_PIXMAP_CONVERT);
436     begin_button = g_list_last(GNOME_DIALOG(upload_window)->buttons)->data;
437     gtk_widget_show(begin_button);
438     GTK_WIDGET_SET_FLAGS(begin_button, GTK_CAN_DEFAULT);
439 
440     gnome_dialog_append_button_with_pixmap(GNOME_DIALOG(upload_window),
441 			       "View Errors", GNOME_STOCK_PIXMAP_SEARCH);
442     error_button = g_list_last(GNOME_DIALOG(upload_window)->buttons)->data;
443     gtk_signal_connect_object(GTK_OBJECT(error_button), "clicked",
444 			      GTK_SIGNAL_FUNC(gtk_widget_show),
445 			      GTK_OBJECT(error_log_window));
446     gtk_widget_show(error_button);
447     gtk_widget_set_sensitive(error_button, FALSE);
448     GTK_WIDGET_SET_FLAGS(error_button, GTK_CAN_DEFAULT);
449 
450     gnome_dialog_append_button(GNOME_DIALOG(upload_window), GNOME_STOCK_BUTTON_CLOSE);
451     close_button = g_list_last(GNOME_DIALOG(upload_window)->buttons)->data;
452     gtk_signal_connect(GTK_OBJECT(close_button), "clicked",
453 		       GTK_SIGNAL_FUNC(close_main_update_window), NULL);
454 /*    gtk_signal_connect_object(GTK_OBJECT(close_button), "clicked",
455 			      GTK_SIGNAL_FUNC(gnome_dialog_close),
456 			      (gpointer) upload_window);
457 */
458     gtk_widget_show(close_button);
459     GTK_WIDGET_SET_FLAGS(close_button, GTK_CAN_DEFAULT);
460 
461    if (strcmp((gchar *)data, "single") == 0) {
462       gtk_signal_connect(GTK_OBJECT(begin_button), "clicked",
463 			 GTK_SIGNAL_FUNC(start_main_update),
464 			 "single");
465    } else if (strcmp((gchar *)data, "all") == 0) {
466       gtk_signal_connect(GTK_OBJECT(begin_button), "clicked",
467 			 GTK_SIGNAL_FUNC(start_main_update),
468 			 "all");
469    } else {
470       g_assert_not_reached();
471    }
472     gtk_widget_show(upload_window);
473     return 2;
474 }
475 
fe_catchup_site(void)476 int fe_catchup_site(void)
477 {
478     if (selected_site == NULL) {
479 	gfe_status("No site has been selected to catch-up.");
480 	return 0;
481     }
482     fe_gtk_question("This will mark ALL files as already updated.\nAre you sure you want to do this?",
483 		    (GnomeReplyCallback) catchup_selected);
484     return 0;
485 }
486 
catchup_selected(gint button_number,gpointer data)487 void catchup_selected(gint button_number, gpointer data)
488 {
489     gchar *result;
490     extern GtkCTreeNode *current_site_node;
491     if (button_number == GNOME_YES) {
492 	site_catchup(selected_site);
493 	result = g_strdup_printf("All files in %s of site %s\nhave been marked as updated.",
494 			 selected_site->local_root, selected_site->name);
495 	gfe_status(result);
496 	g_free(result);
497 	/* On huge sites, this may take ages? Progress bars/locking of ctree
498 	 * selection may be advisable... */
499 	site_write_stored_state(selected_site);
500 	rebuild_node_files(current_site_node);
501     }
502 }
503 
fe_init_site(void)504 int fe_init_site(void)
505 {
506     if (selected_site == NULL) {
507 	gfe_status("No site has been selected to initialise.");
508 	return 0;
509     }
510     fe_gtk_question("This will mark all files as *NOT* updated on the remote site.\nAre you sure you want to do this?",
511 		    (GnomeReplyCallback) initialize_selected);
512     return 0;
513 }
514 
initialize_selected(gint button_number,gpointer data)515 void initialize_selected(gint button_number,
516 			 gpointer data)
517 {
518     gchar *result;
519     extern GtkCTreeNode *current_site_node;
520 
521     switch (button_number) {
522     case GNOME_YES:
523 	site_initialize(selected_site);
524 	result = g_strdup_printf("All files in %s of site '%s'\nhave been marked as *NOT* updated.",
525 			 selected_site->local_root, selected_site->name);
526 	gfe_status(result);
527 	g_free(result);
528 	/* On huge sites, this may take ages? Progress bars/locking of ctree
529 	 * selection may be advisable... */
530 	site_write_stored_state(selected_site);
531 	redraw_main_area();
532 	rebuild_node_files(current_site_node);
533 	break;
534     case GNOME_NO:
535 	break;
536     }
537 }
538 
save_default(void)539 void save_default(void)
540 {
541     extern char *rcfile;
542     extern gboolean rcfile_saved;
543     extern GtkWidget *sitecopy;
544 
545     if (rcfile == NULL) {
546 	gnome_app_error(GNOME_APP(sitecopy), "The current rcfile is set to NULL. Sites will not be saved. Contact the maintainer.");
547 	return;
548     }
549     if (rcfile_write(rcfile, all_sites) == 0) {
550 	gchar *tmp;
551 	tmp = g_strdup_printf("Site definitions saved to %s.", rcfile);
552 	gfe_status(tmp);
553 	g_free(tmp);
554     } else {
555 	gnome_error_dialog("There was an error writing the site definitions.\n They may not have saved correctly.");
556     }
557     rcfile_saved = true;
558 }
559 
delete_a_site(GtkWidget * button_or_menu,gpointer data)560 void delete_a_site(GtkWidget * button_or_menu, gpointer data)
561 {
562     gchar *tmp;
563 
564     if (selected_site == NULL) {
565 	gnome_error_dialog("Cannot perform deletion - no site appears to be selected");
566     } else {
567 	tmp = g_strdup_printf("Are you sure you wish to permanently delete the record of '%s'?",
568 			      selected_site->name);
569 	fe_gtk_question(tmp, (GnomeReplyCallback) (delete_selected));
570     }
571 }
572 
find_prev_site(struct site * a_site)573 struct site *find_prev_site(struct site *a_site)
574 {
575     struct site *tmp;
576     tmp = all_sites;
577     while (tmp->next != NULL) {
578 	if (strcmp(tmp->next->name, selected_site->name) == 0) {
579 	    return tmp;
580 	} else {
581 	    tmp = tmp->next;
582 	}
583     }
584     return NULL;		/* Bad if this ever happens */
585 }
586 
delete_selected(gint button_number)587 void delete_selected(gint button_number)
588 {
589     struct site *tmp, *tmp2;
590     extern GtkCTree *the_tree;
591     extern GtkCTreeNode *current_site_node;
592     extern gboolean rcfile_saved;
593 
594     if (button_number != GNOME_YES)
595 	return;
596     if ((selected_site != NULL) && (all_sites != NULL)) {
597 	if (strcmp(all_sites->name, selected_site->name) == 0) {
598 	    all_sites = all_sites->next;
599 	} else {
600 	    tmp = find_prev_site(selected_site);
601 	    if (tmp->next != NULL) {
602 		tmp2 = tmp->next;
603 		tmp->next = tmp2->next;
604 	    }
605 	}
606 	gtk_ctree_remove_node(GTK_CTREE(the_tree),
607 			      GTK_CTREE_NODE(current_site_node));
608 	selected_site = NULL;
609 	current_site_node = NULL;
610     } else {
611 	gnome_error_dialog("I've detected no site is selected, but one should be selected in order to get here. Oh dear.");
612     }
613     clear_main_area();
614     rcfile_saved = false;
615 }
616 
617