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