Add dirty variable.
[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
501void astcancel(GtkWidget *widget, gpointer uudata)
502{
503 if(ignoreclose)
504 return;
505 gtk_main_quit();
506 state = -1;
507}
508
509#define bufcats(buf, str) bufcat(buf, str, strlen(str))
510
511void astupdate(GtkWidget *widget, GtkWidget *page, gpointer uudata)
512{
513 char *s, *buf;
514 size_t sdata, ssize;
515 struct cfvar *var;
516 GtkTreeIter iter;
517
518 ast2conf();
eb54b70d 519 s = NULL;
520 sdata = ssize = 0;
521 for(var = config; var->name != NULL; var++) {
522 if(var->rname == NULL)
523 continue;
524 bufcats(s, var->rname);
525 bufcats(s, ": ");
526 bufcat(s, var->val, strlen(var->val));
527 addtobuf(s, '\n');
528 }
529 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
530 addtobuf(s, '\n');
531 bufcats(s, _("Shares:\n"));
532 do {
533 addtobuf(s, '\t');
534 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, 1, &buf, -1);
535 bufcats(s, buf);
536 g_free(buf);
537 addtobuf(s, '\n');
538 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
539 }
540 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(ast_summary)), s, sdata);
541 free(s);
542}
543
544void cb_ast_wnd_apply(GtkWidget *widget, gpointer uudata)
545{
546 writeconfig();
547 gtk_main_quit();
0fbd8398 548 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ast_action_dolcon)))
549 state = 2;
550 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ast_action_exit)))
551 state = -1;
552 else
553 state = 0;
554 ignoreclose = 1;
eb54b70d 555}
556
557void cb_ast_nick_changed(GtkWidget *widget, gpointer uudata)
558{
559 if(v_dcstring(gtk_entry_get_text(GTK_ENTRY(ast_nick))))
560 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page1, TRUE);
561 else
562 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page1, FALSE);
563}
564
565int hasshare(int col, char *name)
566{
567 GtkTreeIter iter;
568 char *buf;
569
570 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
571 do {
572 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, col, &buf, -1);
573 if(!strcmp(buf, name)) {
574 g_free(buf);
575 return(1);
576 }
577 g_free(buf);
578 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
579 }
580 return(0);
581}
582
0fbd8398 583int shareadd(void)
eb54b70d 584{
0fbd8398 585 int i, ret;
eb54b70d 586 GSList *fns, *next;
587 char *fn, *sn, *p;
588 GtkTreeIter iter;
589 GtkWidget *chd;
590 int resp;
591
592 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);
593 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(chd), TRUE);
594 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chd), TRUE);
595 resp = gtk_dialog_run(GTK_DIALOG(chd));
596 if(resp != GTK_RESPONSE_ACCEPT) {
597 gtk_widget_destroy(chd);
0fbd8398 598 return(0);
eb54b70d 599 }
0fbd8398 600 ret = 0;
eb54b70d 601 fns = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chd));
602 gtk_widget_destroy(chd);
603 while(fns != NULL) {
604 fn = fns->data;
605 if(!hasshare(1, fn)) {
606 if((p = strrchr(fn, '/')) == NULL)
607 p = fn;
608 else
609 p++;
610 sn = sstrdup(p);
611 if(hasshare(0, sn)) {
612 for(i = 2; 1; i++) {
613 free(sn);
614 sn = sprintf2("%s%i", p, i);
615 if(!hasshare(0, sn))
616 break;
617 }
618 }
619 gtk_list_store_append(shares, &iter);
620 gtk_list_store_set(shares, &iter, 0, sn, 1, fn, -1);
621 free(sn);
0fbd8398 622 ret = 1;
eb54b70d 623 }
624 g_free(fn);
625 next = fns->next;
626 g_slist_free_1(fns);
627 fns = next;
628 }
0fbd8398 629 return(ret);
630}
631
632void cb_ast_shareadd_clicked(GtkWidget *widget, gpointer uudata)
633{
634 if(shareadd())
635 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page2, TRUE);
636}
637
638void cb_cfw_shareadd_clicked(GtkWidget *widget, gpointer uudata)
639{
640 shareadd();
eb54b70d 641}
642
643void cb_ast_sharerem_clicked(GtkWidget *widget, gpointer uudata)
644{
645 GtkTreeIter iter;
646
647 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(ast_sharelist)), NULL, &iter))
648 gtk_list_store_remove(shares, &iter);
649 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(shares), NULL) == 0)
650 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page2, FALSE);
651}
652
0fbd8398 653void cb_cfw_sharerem_clicked(GtkWidget *widget, gpointer uudata)
654{
655 GtkTreeIter iter;
656
657 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(cfw_sharelist)), NULL, &iter))
658 gtk_list_store_remove(shares, &iter);
659}
660
48b166ff 661void cb_ast_checkports(GtkWidget *widget, gpointer uudata)
662{
663 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page3,
664 v_natural(gtk_entry_get_text(GTK_ENTRY(ast_tcpport))) &&
0fbd8398 665 (atoi(gtk_entry_get_text(GTK_ENTRY(ast_tcpport))) >= 1024) &&
48b166ff 666 v_natural(gtk_entry_get_text(GTK_ENTRY(ast_udpport))) &&
0fbd8398 667 (atoi(gtk_entry_get_text(GTK_ENTRY(ast_udpport))) >= 1024) &&
48b166ff 668 v_ipv4(gtk_entry_get_text(GTK_ENTRY(ast_extip))));
669}
670
671void cb_ast_mode_nat_toggled(GtkWidget *widget, gpointer uudata)
672{
673 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
674 gtk_widget_set_sensitive(GTK_WIDGET(ast_portbox), TRUE);
675 cb_ast_checkports(widget, NULL);
676 } else {
677 gtk_widget_set_sensitive(GTK_WIDGET(ast_portbox), FALSE);
678 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page3, TRUE);
679 }
680}
681
0fbd8398 682void cb_cfw_mode_act_toggled(GtkWidget *widget, gpointer uudata)
683{
684 gtk_widget_set_sensitive(GTK_WIDGET(cfw_natbox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
685}
686
687void cb_cfw_orport_toggled(GtkWidget *widget, gpointer uudata)
688{
689 gtk_widget_set_sensitive(GTK_WIDGET(cfw_portbox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
690}
691
692void cb_cfw_oraddr_toggled(GtkWidget *widget, gpointer uudata)
693{
694 gtk_widget_set_sensitive(GTK_WIDGET(cfw_addrbox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
695}
696
697void cb_cfw_uinet_toggled(GtkWidget *widget, gpointer uudata)
698{
699 gtk_widget_set_sensitive(GTK_WIDGET(cfw_uibox), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
700}
701
c8394dc9 702void cb_cfw_save_activate(GtkWidget *widget, gpointer uudata)
0fbd8398 703{
704 struct cfvar *cv;
705
706 for(cv = config; cv->name != NULL; cv++) {
707 if((cv->vld != NULL) && !cv->vld->check(cv->val)) {
708 if(cv->rname) {
709 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, cv->vld->invmsg, cv->rname);
710 } else {
711 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Internal error (Auto-generated variable %s has an invalid value \"%s\")"), cv->name, cv->val);
712 }
713 return;
714 }
715 }
716 cfw2conf();
717 writeconfig();
718}
719
c8394dc9 720void cb_cfw_quit_activate(GtkWidget *widget, gpointer uudata)
0fbd8398 721{
722 gtk_main_quit();
723 state = -1;
724}
725
eb54b70d 726int main(int argc, char **argv)
727{
714e16fb 728 int i, c, ex;
eb54b70d 729 struct passwd *pwd;
730
731 setlocale(LC_ALL, "");
732 bindtextdomain(PACKAGE, LOCALEDIR);
733 textdomain(PACKAGE);
734 prepstatic();
735
736 gtk_init(&argc, &argv);
714e16fb 737 state = -1;
738 while((c = getopt(argc, argv, "haw")) != -1) {
739 switch(c) {
740 case 'a':
741 state = 1;
742 break;
743 case 'w':
744 state = 0;
ee20b80b 745 break;
714e16fb 746 case 'h':
747 default:
748 fprintf((c == 'h')?stdout:stderr, "usage: dolconf [-haw]\n");
cab1ec0e 749 exit((c == 'h')?0:1);
714e16fb 750 }
751 }
752
eb54b70d 753 create_ast_wnd();
0fbd8398 754 create_cfw_wnd();
eb54b70d 755 shares = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
756 gtk_tree_view_set_model(GTK_TREE_VIEW(ast_sharelist), GTK_TREE_MODEL(shares));
0fbd8398 757 gtk_tree_view_set_model(GTK_TREE_VIEW(cfw_sharelist), GTK_TREE_MODEL(shares));
eb54b70d 758
759 cfname = NULL;
760 if(getenv("HOME") != NULL) {
761 cfname = sprintf2("%s/.doldacond.conf", getenv("HOME"));
762 } else {
763 if((pwd = getpwuid(getuid())) != NULL)
764 cfname = sprintf2("%s/.doldacond.conf", pwd->pw_dir);
765 }
766 if(cfname == NULL) {
767 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not get your home directory!"));
768 exit(1);
769 }
770
714e16fb 771 ex = !access(cfname, F_OK);
c8394dc9 772 if(state == -1) {
773 if(!ex) {
774 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)
775 state = 1;
776 else
777 state = 0;
778 } else {
0fbd8398 779 state = 0;
c8394dc9 780 }
714e16fb 781 }
782
783 if(ex && (state == 0)) {
eb54b70d 784 if(readconfig() == 1) {
785 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)
786 exit(1);
787 }
788 }
714e16fb 789
0fbd8398 790 while(state != -1) {
791 if(state == 0) {
792 gtk_window_set_default_size(GTK_WINDOW(cfw_wnd), 500, 350);
793 gtk_widget_show(cfw_wnd);
794 fillcfw();
795 rootwnd = GTK_WINDOW(cfw_wnd);
796 gtk_main();
797 gtk_widget_hide(cfw_wnd);
798 rootwnd = NULL;
799 } else if(state == 1) {
800 gtk_window_set_default_size(GTK_WINDOW(ast_wnd), 500, 350);
801 gtk_widget_show(ast_wnd);
802 rootwnd = GTK_WINDOW(ast_wnd);
803 gtk_main();
804 gtk_widget_hide(ast_wnd);
805 ignoreclose = 0;
806 rootwnd = NULL;
807 } else if(state == 2) {
808 for(i = 3; i < FD_SETSIZE; i++)
809 close(i);
810 execlp("dolcon", "dolcon", NULL);
811 perror("dolcon");
812 exit(127);
813 } else {
814 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Internal error (Unknown state)"));
815 abort();
816 }
817 }
eb54b70d 818 return(0);
819}