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