A couple of bugfixes in dolconf.
[doldaconnect.git] / config / util / dolconf.c
CommitLineData
eb54b70d 1/*
2 * Dolda Connect - Modular multiuser Direct Connect-style client
714e16fb 3 * Copyright (C) 2007 Fredrik Tolf <fredrik@dolda2000.com>
eb54b70d 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <unistd.h>
23#include <string.h>
24#include <ctype.h>
25#include <signal.h>
26#include <errno.h>
27#include <gtk/gtk.h>
c8394dc9 28#include <gdk/gdkkeysyms.h>
eb54b70d 29#include <locale.h>
30#include <libintl.h>
31#include <pwd.h>
32#include <stdarg.h>
48b166ff 33#include <arpa/inet.h>
c3aa1aa0 34#include <doldaconnect/uilib.h>
35#include <doldaconnect/uimisc.h>
eb54b70d 36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40#include <utils.h>
41
42struct validation {
43 int (*check)(const char *val);
44 char *invmsg;
45};
46
47struct cfvar {
48 char *name;
49 char *rname;
50 char *val;
51 struct validation *vld;
0fbd8398 52 GtkWidget **astw, **cfww;
eb54b70d 53};
54
55char *cfname;
56GtkWindow *rootwnd = NULL;
57GtkListStore *shares;
c8394dc9 58int state, dirty = 1;
0fbd8398 59int ignoreclose = 0;
60
0fbd8398 61#define _(text) gettext(text)
62
b1099f1f
FT
63#include "dolconf-assistant.gtkh"
64#include "dolconf-wnd.gtkh"
eb54b70d 65
66int v_nonempty(const char *val)
67{
68 return(strlen(val) > 0);
69}
70
71int v_dcstring(const char *val)
72{
73 return((strchr(val, ' ') == NULL) &&
74 (strchr(val, '|') == NULL) &&
75 (strchr(val, '$') == NULL));
76}
77
48b166ff 78int v_natural(const char *val)
eb54b70d 79{
48b166ff 80 if(!*val)
81 return(0);
82 for(; *val; val++) {
83 if(!isdigit(*val))
eb54b70d 84 return(0);
85 }
86 return(1);
87}
88
48b166ff 89int v_integer(const char *val)
90{
91 int f, d;
92
93 for(f = 1, d = 0; *val; val++, f = 0) {
94 if(isdigit(*val)) {
95 d = 1;
96 } else if(f && (*val == '-')) {
97 } else {
98 return(0);
99 }
100 }
101 return(d);
102}
103
104int v_ipv4(const char *val)
105{
106 struct in_addr buf;
107
108 return(inet_aton(val, &buf) != 0);
109}
110
0fbd8398 111#undef _
eb54b70d 112#define _(text) text
113
114struct validation nonempty = {
115 .check = v_nonempty,
116 .invmsg = _("%s must not be empty"),
117};
118
119struct validation dcstring = {
120 .check = v_dcstring,
121 .invmsg = _("%s must not contain spaces, `|' or `$'"),
122};
123
48b166ff 124struct validation natural = {
125 .check = v_natural,
126 .invmsg = _("%s must be a natural number"),
127};
128
129struct validation integer = {
130 .check = v_integer,
131 .invmsg = _("%s must be an integer"),
132};
133
134struct validation ipv4 = {
135 .check = v_ipv4,
136 .invmsg = _("%s must be an IP address"),
eb54b70d 137};
138
139struct validation *vldxlate[] = {
48b166ff 140 &nonempty, &dcstring, &natural, &integer, &ipv4,
eb54b70d 141 NULL
142};
143
144struct cfvar config[] = {
0fbd8398 145 {"cli.defnick", _("Screen name"), "", &dcstring, &ast_nick, &cfw_nick},
48b166ff 146 {"net.mode", NULL, "0", &natural},
0fbd8398 147 {"net.visibleipv4", "IP address", "0.0.0.0", &ipv4, NULL, &cfw_extip},
48b166ff 148 {"ui.onlylocal", NULL, "0", &natural},
149 {"ui.port", NULL, "-1", &integer},
150 {"auth.authless", NULL, "0", &natural},
151 {"transfer.slots", _("Upload slots"), "6", &natural},
0fbd8398 152 {"dc.speedstring", _("Connection speed"), "DSL", &dcstring, NULL, &cfw_cntype},
153 {"dc.email", _("E-mail address"), "spam@spam.net", &dcstring, NULL, &cfw_mail},
154 {"dc.desc", _("Share description"), "", NULL, &ast_desc, &cfw_desc},
155 {"dc.tcpport", _("Direct Connect TCP port"), "0", &natural, NULL, &cfw_tcpport},
156 {"dc.udpport", _("Direct Connect UDP port"), "0", &natural, NULL, &cfw_udpport},
eb54b70d 157 {NULL}
158};
159
160#undef _
161#define _(text) gettext(text)
162
eb54b70d 163struct cfvar *findcfvar(char *name)
164{
165 struct cfvar *v;
166
167 for(v = config; v->name != NULL; v++) {
168 if(!strcmp(v->name, name))
169 return(v);
170 }
171 return(NULL);
172}
173
174void setcfvar(char *name, const char *val)
175{
176 struct cfvar *v;
177
178 v = findcfvar(name);
c8394dc9 179 if(!strcmp(v->val, val))
180 return;
eb54b70d 181 free(v->val);
182 v->val = sstrdup(val);
c8394dc9 183 dirty = 1;
eb54b70d 184}
185
186int msgbox(int type, int buttons, char *format, ...)
187{
188 GtkWidget *swnd;
189 va_list args;
190 char *buf;
191 int resp;
192
193 va_start(args, format);
194 buf = vsprintf2(format, args);
195 va_end(args);
196 swnd = gtk_message_dialog_new(rootwnd, GTK_DIALOG_MODAL, type, buttons, "%s", buf);
197 gtk_window_set_title(GTK_WINDOW(swnd), _("Dolda Connect configurator"));
198 resp = gtk_dialog_run(GTK_DIALOG(swnd));
199 gtk_widget_destroy(swnd);
200 free(buf);
201 return(resp);
202}
203
204void prepstatic(void)
205{
206 struct validation **v;
207 struct cfvar *c;
208
209 for(v = vldxlate; *v != NULL; v++)
210 (*v)->invmsg = gettext((*v)->invmsg);
211 for(c = config; c->name != NULL; c++) {
212 if(c->rname != NULL)
213 c->rname = gettext(c->rname);
214 c->val = sstrdup(c->val);
215 }
216}
217
218char *getword(char **p)
219{
220 char *buf, *p2, delim;
221 size_t len;
222
223 if(**p == '\"')
224 delim = '\"';
225 else
226 delim = ' ';
227 p2 = *p;
228 while((p2 = strchr(p2 + 1, delim)) != NULL) {
229 if(p2[-1] != '\\')
230 break;
231 }
232 if(p2 == NULL)
233 p2 = *p + strlen(*p);
0fbd8398 234 len = p2 - *p - ((*p2 == '\"')?1:0);
eb54b70d 235 buf = smalloc(len + 1);
42aa110f 236 memcpy(buf, *p + ((delim == '\"')?1:0), len);
eb54b70d 237 buf[len] = 0;
238 *p = p2 + ((*p2 == '\"')?1:0);
239 for(p2 = buf; *p2; p2++, len--) {
240 if(*p2 == '\\')
241 memmove(p2, p2 + 1, len--);
242 }
243 return(buf);
244}
245
246char *quoteword(char *word)
247{
248 char *wp, *buf, *bp;
249 int dq, numbs, numc;
250
251 dq = 0;
252 numbs = 0;
253 numc = 0;
254 if(*word == '\0')
255 {
256 dq = 1;
257 } else {
258 for(wp = word; *wp != '\0'; wp++)
259 {
260 if(!dq && isspace(*wp))
261 dq = 1;
262 if((*wp == '\\') || (*wp == '\"'))
263 numbs++;
264 numc++;
265 }
266 }
267 if(!dq && !numbs)
268 return(NULL);
269 bp = buf = smalloc(sizeof(wchar_t) * (numc + numbs + (dq?2:0) + 1));
270 if(dq)
271 *(bp++) = '\"';
272 for(wp = word; *wp != '\0'; wp++)
273 {
274 if((*wp == '\\') || (*wp == '\"'))
275 *(bp++) = '\\';
276 *(bp++) = *wp;
277 }
278 if(dq)
279 *(bp++) = '\"';
280 *(bp++) = '\0';
281 return(buf);
282}
283
284int readconfig(void)
285{
286 int rv;
287 FILE *cf;
288 char lbuf[1024];
289 char *key, *val, *p;
290 size_t len;
291 struct cfvar *var;
292 GtkTreeIter iter;
293
294 rv = 0;
295 if((cf = fopen(cfname, "r")) == NULL) {
296 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Could not open the configuration file for reading: %s"), strerror(errno));
297 return(-1);
298 }
299 key = val = NULL;
300 while(fgets(lbuf, sizeof(lbuf), cf) != NULL) {
301 len = strlen(lbuf);
302 if(lbuf[len - 1] == '\n')
303 lbuf[len - 1] = 0;
304 if(key != NULL) {
305 free(key);
306 key = NULL;
307 }
308 if(val != NULL) {
309 free(val);
310 val = NULL;
311 }
312 if(!strncmp(lbuf, "set ", 4)) {
313 p = lbuf + 4;
314 if(((key = getword(&p)) == NULL) || (*(p++) != ' ') || ((val = getword(&p)) == NULL)) {
315 rv = 1;
316 continue;
317 }
318 for(var = config; var->name != NULL; var++) {
319 if(!strcmp(var->name, key)) {
320 free(var->val);
321 var->val = sstrdup(val);
322 break;
323 }
324 }
325 if(var->name == NULL)
326 rv = 1;
327 } else if(!strncmp(lbuf, "share ", 6)) {
328 p = lbuf + 6;
329 if(((key = getword(&p)) == NULL) || (*(p++) != ' ') || ((val = getword(&p)) == NULL)) {
330 rv = 1;
331 continue;
332 }
333 gtk_list_store_append(shares, &iter);
334 gtk_list_store_set(shares, &iter, 0, key, 1, val, -1);
335 } else if(!lbuf[0] || lbuf[0] == '#') {
336 } else {
337 rv = 1;
338 }
339 }
340 if(key != NULL)
341 free(key);
342 if(val != NULL)
343 free(val);
344 fclose(cf);
c8394dc9 345 dirty = 0;
eb54b70d 346 return(rv);
347}
348
5668485c 349int writeconfig(void)
eb54b70d 350{
351 FILE *cf;
352 struct cfvar *var;
353 GtkTreeIter iter;
354 char *buf, *buf2;
355
356 if((cf = fopen(cfname, "w")) == NULL) {
357 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Could not open the configuration file for writing: %s"), strerror(errno));
5668485c 358 return(-1);
eb54b70d 359 }
360 fputs("# This file was generated by dolconf v" VERSION "\n\n", cf);
361 for(var = config; var->name != NULL; var++) {
362 fprintf(cf, "set %s ", var->name);
363 if((buf = quoteword(var->val)) == NULL) {
364 fputs(var->val, cf);
365 } else {
366 fputs(buf, cf);
367 free(buf);
368 }
369 fputc('\n', cf);
370 }
371 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
372 fputc('\n', cf);
373 do {
374 fputs("share ", cf);
375 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, 0, &buf2, -1);
376 if((buf = quoteword(buf2)) == NULL) {
377 fputs(buf2, cf);
378 } else {
379 fputs(buf, cf);
380 free(buf);
381 }
382 g_free(buf2);
383 fputc(' ', cf);
384 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, 1, &buf2, -1);
385 if((buf = quoteword(buf2)) == NULL) {
386 fputs(buf2, cf);
387 } else {
388 fputs(buf, cf);
389 free(buf);
390 }
391 g_free(buf2);
392 fputc('\n', cf);
393 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
394 }
395 fclose(cf);
c8394dc9 396 dirty = 0;
5668485c 397 return(0);
eb54b70d 398}
399
0fbd8398 400void fillcfw(void)
eb54b70d 401{
0fbd8398 402 struct cfvar *var;
403
404 for(var = config; var->name != NULL; var++) {
405 if(var->cfww != NULL)
406 gtk_entry_set_text(GTK_ENTRY(*(var->cfww)), var->val);
407 }
408 if(atoi(findcfvar("dc.tcpport")->val) || atoi(findcfvar("dc.udpport")->val))
409 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_orport), TRUE);
410 else
411 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_orport), FALSE);
412 if(strcmp(findcfvar("net.visibleipv4")->val, "0.0.0.0"))
413 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_oraddr), TRUE);
414 else
415 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_oraddr), FALSE);
416 if(strcmp(findcfvar("ui.port")->val, "-1")) {
417 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_uinet), TRUE);
418 if(strcmp(findcfvar("auth.authless")->val, "1"))
419 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_authless), FALSE);
420 else
421 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_authless), TRUE);
422 } else {
423 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_uinet), FALSE);
424 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfw_authless), FALSE);
425 }
eb54b70d 426}
427
0fbd8398 428void ast2conf(void)
eb54b70d 429{
eb54b70d 430 setcfvar("cli.defnick", gtk_entry_get_text(GTK_ENTRY(ast_nick)));
431 setcfvar("dc.desc", gtk_entry_get_text(GTK_ENTRY(ast_desc)));
48b166ff 432 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ast_mode_psv))) {
433 setcfvar("net.mode", "1");
434 } else {
435 setcfvar("net.mode", "0");
436 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ast_mode_nat))) {
437 setcfvar("net.visibleipv4", gtk_entry_get_text(GTK_ENTRY(ast_extip)));
438 setcfvar("dc.tcpport", gtk_entry_get_text(GTK_ENTRY(ast_udpport)));
439 setcfvar("dc.udpport", gtk_entry_get_text(GTK_ENTRY(ast_tcpport)));
440 } else {
441 setcfvar("net.visibleipv4", "0.0.0.0");
442 setcfvar("dc.tcpport", "0");
443 setcfvar("dc.udpport", "0");
444 }
445 }
0fbd8398 446}
447
448void cfw2conf(void)
449{
450 struct cfvar *var;
c8394dc9 451 const char *val;
0fbd8398 452
453 for(var = config; var->name != NULL; var++) {
454 if(var->cfww != NULL) {
c8394dc9 455 val = gtk_entry_get_text(GTK_ENTRY(*(var->cfww)));
456 if(!strcmp(var->val, val))
457 continue;
0fbd8398 458 free(var->val);
c8394dc9 459 var->val = sstrdup(val);
460 dirty = 1;
0fbd8398 461 }
462 }
463 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cfw_mode_act))) {
464 setcfvar("net.mode", "0");
465 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cfw_orport))) {
466 setcfvar("dc.tcpport", "0");
467 setcfvar("dc.udpport", "0");
468 }
469 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cfw_oraddr))) {
470 setcfvar("net.visibleipv4", "0.0.0.0");
471 }
472 } else {
473 setcfvar("net.mode", "1");
474 }
475 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cfw_uinet))) {
476 setcfvar("ui.port", "1500");
477 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cfw_authless)))
478 setcfvar("auth.authless", "1");
479 else
480 setcfvar("auth.authless", "0");
481 } else {
482 setcfvar("ui.port", "-1");
483 setcfvar("auth.authless", "0");
484 }
485}
486
958a04bd 487struct cfvar *cfwvalid(void)
488{
489 struct cfvar *cv;
490
491 for(cv = config; cv->name != NULL; cv++) {
492 if((cv->vld != NULL) && !cv->vld->check(cv->val)) {
493 if(cv->rname) {
494 return(cv);
495 } else {
496 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Internal error (Auto-generated variable %s has an invalid value \"%s\")"), cv->name, cv->val);
497 abort();
498 }
499 }
500 }
501 return(NULL);
502}
503
0fbd8398 504void astcancel(GtkWidget *widget, gpointer uudata)
505{
506 if(ignoreclose)
507 return;
508 gtk_main_quit();
509 state = -1;
510}
511
512#define bufcats(buf, str) bufcat(buf, str, strlen(str))
513
514void astupdate(GtkWidget *widget, GtkWidget *page, gpointer uudata)
515{
516 char *s, *buf;
517 size_t sdata, ssize;
518 struct cfvar *var;
519 GtkTreeIter iter;
520
521 ast2conf();
eb54b70d 522 s = NULL;
523 sdata = ssize = 0;
524 for(var = config; var->name != NULL; var++) {
525 if(var->rname == NULL)
526 continue;
527 bufcats(s, var->rname);
528 bufcats(s, ": ");
529 bufcat(s, var->val, strlen(var->val));
530 addtobuf(s, '\n');
531 }
532 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
533 addtobuf(s, '\n');
534 bufcats(s, _("Shares:\n"));
535 do {
536 addtobuf(s, '\t');
537 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, 1, &buf, -1);
538 bufcats(s, buf);
539 g_free(buf);
540 addtobuf(s, '\n');
541 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
542 }
543 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(ast_summary)), s, sdata);
544 free(s);
545}
546
547void cb_ast_wnd_apply(GtkWidget *widget, gpointer uudata)
548{
549 writeconfig();
550 gtk_main_quit();
0fbd8398 551 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ast_action_dolcon)))
552 state = 2;
553 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ast_action_exit)))
554 state = -1;
555 else
556 state = 0;
557 ignoreclose = 1;
eb54b70d 558}
559
560void cb_ast_nick_changed(GtkWidget *widget, gpointer uudata)
561{
562 if(v_dcstring(gtk_entry_get_text(GTK_ENTRY(ast_nick))))
563 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page1, TRUE);
564 else
565 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page1, FALSE);
566}
567
568int hasshare(int col, char *name)
569{
570 GtkTreeIter iter;
571 char *buf;
572
573 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
574 do {
575 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, col, &buf, -1);
576 if(!strcmp(buf, name)) {
577 g_free(buf);
578 return(1);
579 }
580 g_free(buf);
581 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
582 }
583 return(0);
584}
585
0fbd8398 586int shareadd(void)
eb54b70d 587{
0fbd8398 588 int i, ret;
eb54b70d 589 GSList *fns, *next;
590 char *fn, *sn, *p;
591 GtkTreeIter iter;
592 GtkWidget *chd;
593 int resp;
594
595 chd = gtk_file_chooser_dialog_new(_("Shared directories"), rootwnd, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
596 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(chd), TRUE);
597 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chd), TRUE);
598 resp = gtk_dialog_run(GTK_DIALOG(chd));
599 if(resp != GTK_RESPONSE_ACCEPT) {
600 gtk_widget_destroy(chd);
0fbd8398 601 return(0);
eb54b70d 602 }
0fbd8398 603 ret = 0;
eb54b70d 604 fns = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chd));
605 gtk_widget_destroy(chd);
606 while(fns != NULL) {
607 fn = fns->data;
608 if(!hasshare(1, fn)) {
609 if((p = strrchr(fn, '/')) == NULL)
610 p = fn;
611 else
612 p++;
613 sn = sstrdup(p);
614 if(hasshare(0, sn)) {
615 for(i = 2; 1; i++) {
616 free(sn);
617 sn = sprintf2("%s%i", p, i);
618 if(!hasshare(0, sn))
619 break;
620 }
621 }
622 gtk_list_store_append(shares, &iter);
623 gtk_list_store_set(shares, &iter, 0, sn, 1, fn, -1);
624 free(sn);
0fbd8398 625 ret = 1;
eb54b70d 626 }
627 g_free(fn);
628 next = fns->next;
629 g_slist_free_1(fns);
630 fns = next;
631 }
0fbd8398 632 return(ret);
633}
634
635void cb_ast_shareadd_clicked(GtkWidget *widget, gpointer uudata)
636{
637 if(shareadd())
638 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page2, TRUE);
639}
640
641void cb_cfw_shareadd_clicked(GtkWidget *widget, gpointer uudata)
642{
c335e21c
FT
643 if(shareadd())
644 dirty = 1;
eb54b70d 645}
646
647void cb_ast_sharerem_clicked(GtkWidget *widget, gpointer uudata)
648{
649 GtkTreeIter iter;
650
651 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(ast_sharelist)), NULL, &iter))
652 gtk_list_store_remove(shares, &iter);
653 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(shares), NULL) == 0)
654 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page2, FALSE);
655}
656
0fbd8398 657void cb_cfw_sharerem_clicked(GtkWidget *widget, gpointer uudata)
658{
659 GtkTreeIter iter;
660
c335e21c 661 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(cfw_sharelist)), NULL, &iter)) {
0fbd8398 662 gtk_list_store_remove(shares, &iter);
c335e21c
FT
663 dirty = 1;
664 }
0fbd8398 665}
666
48b166ff 667void cb_ast_checkports(GtkWidget *widget, gpointer uudata)
668{
669 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page3,
670 v_natural(gtk_entry_get_text(GTK_ENTRY(ast_tcpport))) &&
0fbd8398 671 (atoi(gtk_entry_get_text(GTK_ENTRY(ast_tcpport))) >= 1024) &&
48b166ff 672 v_natural(gtk_entry_get_text(GTK_ENTRY(ast_udpport))) &&
0fbd8398 673 (atoi(gtk_entry_get_text(GTK_ENTRY(ast_udpport))) >= 1024) &&
48b166ff 674 v_ipv4(gtk_entry_get_text(GTK_ENTRY(ast_extip))));
675}
676
677void cb_ast_mode_nat_toggled(GtkWidget *widget, gpointer uudata)
678{
679 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
680 gtk_widget_set_sensitive(GTK_WIDGET(ast_portbox), TRUE);
681 cb_ast_checkports(widget, NULL);
682 } else {
683 gtk_widget_set_sensitive(GTK_WIDGET(ast_portbox), FALSE);
684 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page3, TRUE);
685 }
686}
687
0fbd8398 688void cb_cfw_mode_act_toggled(GtkWidget *widget, gpointer uudata)
689{
690 gtk_widget_set_sensitive(GTK_WIDGET(cfw_natbox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
691}
692
693void cb_cfw_orport_toggled(GtkWidget *widget, gpointer uudata)
694{
695 gtk_widget_set_sensitive(GTK_WIDGET(cfw_portbox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
696}
697
698void cb_cfw_oraddr_toggled(GtkWidget *widget, gpointer uudata)
699{
700 gtk_widget_set_sensitive(GTK_WIDGET(cfw_addrbox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
701}
702
703void cb_cfw_uinet_toggled(GtkWidget *widget, gpointer uudata)
704{
705 gtk_widget_set_sensitive(GTK_WIDGET(cfw_uibox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
706}
707
5668485c 708int hupserver(int disperr)
c3aa1aa0 709{
5668485c 710 int tag, ret;
c3aa1aa0 711 struct dc_response *resp;
712
713 if(dc_connectsync2(dc_srv_local, DC_LATEST) < 0) {
5668485c
FT
714 if(disperr)
715 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server"));
716 return(-1);
c3aa1aa0 717 }
718 if(dc_login(NULL, 1, dc_convnone, NULL) != DC_LOGIN_ERR_SUCCESS) {
719 dc_disconnect();
5668485c
FT
720 if(disperr)
721 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server"));
722 return(-1);
c3aa1aa0 723 }
5668485c 724 ret = 0;
c3aa1aa0 725 tag = dc_queuecmd(NULL, NULL, L"hup", NULL);
726 if((resp = dc_gettaggedrespsync(tag)) != NULL) {
5668485c
FT
727 if(resp->code != 200) {
728 if(disperr)
729 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server"));
730 ret = -1;
731 }
c3aa1aa0 732 dc_freeresp(resp);
733 }
734 dc_disconnect();
5668485c
FT
735 return(ret);
736}
737
738int saveconfig(void)
739{
740 struct cfvar *cv;
741
42aa110f 742 cfw2conf();
5668485c
FT
743 if((cv = cfwvalid()) != NULL) {
744 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, cv->vld->invmsg, cv->rname);
745 return(-1);
746 }
5668485c
FT
747 return(writeconfig());
748}
749
750/*
751void cb_cfw_hup_activate(GtkWidget *widget, gpointer uudata)
752{
753 hupserver(1);
c3aa1aa0 754}
755
c8394dc9 756void cb_cfw_save_activate(GtkWidget *widget, gpointer uudata)
0fbd8398 757{
758 struct cfvar *cv;
759
958a04bd 760 if((cv = cfwvalid()) != NULL) {
761 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, cv->vld->invmsg, cv->rname);
762 return;
0fbd8398 763 }
764 cfw2conf();
765 writeconfig();
766}
767
c8394dc9 768void cb_cfw_quit_activate(GtkWidget *widget, gpointer uudata)
0fbd8398 769{
958a04bd 770 cfw2conf();
771 if(dirty) {
1a724a90 772 if(msgbox(GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("There are unsaved changes. Do you wish to discard the changes and exit anyway?")) == GTK_RESPONSE_NO)
958a04bd 773 return;
774 }
0fbd8398 775 gtk_main_quit();
776 state = -1;
777}
5668485c
FT
778*/
779
42aa110f 780void cb_cfw_ok_clicked(GtkWidget *widget, gpointer uudata)
5668485c
FT
781{
782 if(saveconfig())
783 return;
784 hupserver(0);
785 gtk_main_quit();
786 state = -1;
787}
788
42aa110f 789void cb_cfw_cancel_clicked(GtkWidget *widget, gpointer uudata)
5668485c
FT
790{
791 gtk_main_quit();
792 state = -1;
793}
794
42aa110f 795void cb_cfw_apply_clicked(GtkWidget *widget, gpointer uudata)
5668485c
FT
796{
797 if(saveconfig())
798 return;
799 hupserver(1);
800}
0fbd8398 801
eb54b70d 802int main(int argc, char **argv)
803{
714e16fb 804 int i, c, ex;
eb54b70d 805 struct passwd *pwd;
806
807 setlocale(LC_ALL, "");
808 bindtextdomain(PACKAGE, LOCALEDIR);
809 textdomain(PACKAGE);
810 prepstatic();
c3aa1aa0 811 dc_init();
eb54b70d 812
813 gtk_init(&argc, &argv);
714e16fb 814 state = -1;
8af979f3 815 while((c = getopt(argc, argv, "hawV")) != -1) {
714e16fb 816 switch(c) {
817 case 'a':
818 state = 1;
819 break;
820 case 'w':
821 state = 0;
ee20b80b 822 break;
714e16fb 823 case 'h':
289fa2ea 824 printf("usage: dolconf [-haw]\n");
825 printf("\t-h\tDisplay this help message\n");
826 printf("\t-a\tGo directly to the assistant\n");
827 printf("\t-w\tGo directly to the standard window\n");
8af979f3
FT
828 printf("\t-V\tDisplay version info and exit\n");
829 exit(0);
830 case 'V':
831 printf("%s", RELEASEINFO);
289fa2ea 832 exit(0);
714e16fb 833 default:
8af979f3 834 fprintf(stderr, "usage: dolconf [-hawV]\n");
289fa2ea 835 exit(1);
714e16fb 836 }
837 }
838
eb54b70d 839 create_ast_wnd();
0fbd8398 840 create_cfw_wnd();
eb54b70d 841 shares = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
842 gtk_tree_view_set_model(GTK_TREE_VIEW(ast_sharelist), GTK_TREE_MODEL(shares));
0fbd8398 843 gtk_tree_view_set_model(GTK_TREE_VIEW(cfw_sharelist), GTK_TREE_MODEL(shares));
eb54b70d 844
845 cfname = NULL;
846 if(getenv("HOME") != NULL) {
847 cfname = sprintf2("%s/.doldacond.conf", getenv("HOME"));
848 } else {
849 if((pwd = getpwuid(getuid())) != NULL)
850 cfname = sprintf2("%s/.doldacond.conf", pwd->pw_dir);
851 }
852 if(cfname == NULL) {
853 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not get your home directory!"));
854 exit(1);
855 }
856
714e16fb 857 ex = !access(cfname, F_OK);
c8394dc9 858 if(state == -1) {
859 if(!ex) {
860 if(msgbox(GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("It appears that you have not run this setup program before. Would you like to run the first-time setup assistant?")) == GTK_RESPONSE_YES)
861 state = 1;
862 else
863 state = 0;
864 } else {
0fbd8398 865 state = 0;
c8394dc9 866 }
714e16fb 867 }
868
869 if(ex && (state == 0)) {
eb54b70d 870 if(readconfig() == 1) {
871 if(msgbox(GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("The configuration file appears to have been edited outside the control of this program. If you continue using this program, all settings not handled by it will be lost. Do you wish to continue?")) == GTK_RESPONSE_NO)
872 exit(1);
873 }
874 }
714e16fb 875
0fbd8398 876 while(state != -1) {
877 if(state == 0) {
878 gtk_window_set_default_size(GTK_WINDOW(cfw_wnd), 500, 350);
879 gtk_widget_show(cfw_wnd);
880 fillcfw();
881 rootwnd = GTK_WINDOW(cfw_wnd);
882 gtk_main();
883 gtk_widget_hide(cfw_wnd);
884 rootwnd = NULL;
885 } else if(state == 1) {
886 gtk_window_set_default_size(GTK_WINDOW(ast_wnd), 500, 350);
887 gtk_widget_show(ast_wnd);
888 rootwnd = GTK_WINDOW(ast_wnd);
889 gtk_main();
890 gtk_widget_hide(ast_wnd);
891 ignoreclose = 0;
892 rootwnd = NULL;
893 } else if(state == 2) {
894 for(i = 3; i < FD_SETSIZE; i++)
895 close(i);
11146491
FT
896 execlp("dolcon-launch", "dolcon-launch", NULL);
897 perror("dolcon-launch");
0fbd8398 898 exit(127);
899 } else {
900 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Internal error (Unknown state)"));
901 abort();
902 }
903 }
eb54b70d 904 return(0);
905}
b1099f1f
FT
906
907#include "dolconf-assistant.gtk"
908#include "dolconf-wnd.gtk"