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