2 * Dolda Connect - Modular multiuser Direct Connect-style client
3 * Copyright (C) 2007 Fredrik Tolf (fredrik@dolda2000.com)
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.
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.
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
39 int (*check)(const char *val);
47 struct validation *vld;
51 GtkWindow *rootwnd = NULL;
54 int v_nonempty(const char *val)
56 return(strlen(val) > 0);
59 int v_dcstring(const char *val)
61 return((strchr(val, ' ') == NULL) &&
62 (strchr(val, '|') == NULL) &&
63 (strchr(val, '$') == NULL));
66 int v_numeric(const char *val)
70 for(f = 1; *val; val++, f = 0) {
71 if(!isdigit(val) && (!f || (*val != '-')))
79 struct validation nonempty = {
81 .invmsg = _("%s must not be empty"),
84 struct validation dcstring = {
86 .invmsg = _("%s must not contain spaces, `|' or `$'"),
89 struct validation numeric = {
91 .invmsg = _("%s must be numeric"),
94 struct validation *vldxlate[] = {
95 &nonempty, &dcstring, &numeric,
99 struct cfvar config[] = {
100 {"cli.defnick", _("Nickname"), "", &dcstring},
101 {"net.mode", NULL, "0", &numeric},
102 {"ui.onlylocal", NULL, "0", &numeric},
103 {"auth.authless", NULL, "0", &numeric},
104 {"transfer.slots", _("Upload slots"), "6", &numeric},
105 {"dc.speedstring", _("Connection speed"), "DSL", &dcstring},
106 {"dc.desc", _("Share description"), "", NULL},
111 #define _(text) gettext(text)
113 void astcancel(GtkWidget *widget, gpointer uudata);
114 void astupdate(GtkWidget *widget, GtkWidget *page, gpointer uudata);
115 void cb_ast_wnd_apply(GtkWidget *widget, gpointer uudata);
116 void cb_ast_nick_changed(GtkWidget *widget, gpointer uudata);
117 void cb_ast_shareadd_clicked(GtkWidget *widget, gpointer uudata);
118 void cb_ast_sharerem_clicked(GtkWidget *widget, gpointer uudata);
120 #include "dolconf-assistant.gtk"
122 struct cfvar *findcfvar(char *name)
126 for(v = config; v->name != NULL; v++) {
127 if(!strcmp(v->name, name))
133 void setcfvar(char *name, const char *val)
139 v->val = sstrdup(val);
142 int msgbox(int type, int buttons, char *format, ...)
149 va_start(args, format);
150 buf = vsprintf2(format, args);
152 swnd = gtk_message_dialog_new(rootwnd, GTK_DIALOG_MODAL, type, buttons, "%s", buf);
153 gtk_window_set_title(GTK_WINDOW(swnd), _("Dolda Connect configurator"));
154 resp = gtk_dialog_run(GTK_DIALOG(swnd));
155 gtk_widget_destroy(swnd);
160 void prepstatic(void)
162 struct validation **v;
165 for(v = vldxlate; *v != NULL; v++)
166 (*v)->invmsg = gettext((*v)->invmsg);
167 for(c = config; c->name != NULL; c++) {
169 c->rname = gettext(c->rname);
170 c->val = sstrdup(c->val);
174 char *getword(char **p)
176 char *buf, *p2, delim;
184 while((p2 = strchr(p2 + 1, delim)) != NULL) {
189 p2 = *p + strlen(*p);
191 buf = smalloc(len + 1);
192 memcpy(buf, *p, len);
194 *p = p2 + ((*p2 == '\"')?1:0);
195 for(p2 = buf; *p2; p2++, len--) {
197 memmove(p2, p2 + 1, len--);
202 char *quoteword(char *word)
214 for(wp = word; *wp != '\0'; wp++)
216 if(!dq && isspace(*wp))
218 if((*wp == '\\') || (*wp == '\"'))
225 bp = buf = smalloc(sizeof(wchar_t) * (numc + numbs + (dq?2:0) + 1));
228 for(wp = word; *wp != '\0'; wp++)
230 if((*wp == '\\') || (*wp == '\"'))
251 if((cf = fopen(cfname, "r")) == NULL) {
252 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Could not open the configuration file for reading: %s"), strerror(errno));
256 while(fgets(lbuf, sizeof(lbuf), cf) != NULL) {
258 if(lbuf[len - 1] == '\n')
268 if(!strncmp(lbuf, "set ", 4)) {
270 if(((key = getword(&p)) == NULL) || (*(p++) != ' ') || ((val = getword(&p)) == NULL)) {
274 for(var = config; var->name != NULL; var++) {
275 if(!strcmp(var->name, key)) {
277 var->val = sstrdup(val);
281 if(var->name == NULL)
283 } else if(!strncmp(lbuf, "share ", 6)) {
285 if(((key = getword(&p)) == NULL) || (*(p++) != ' ') || ((val = getword(&p)) == NULL)) {
289 gtk_list_store_append(shares, &iter);
290 gtk_list_store_set(shares, &iter, 0, key, 1, val, -1);
291 } else if(!lbuf[0] || lbuf[0] == '#') {
304 void writeconfig(void)
311 if((cf = fopen(cfname, "w")) == NULL) {
312 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Could not open the configuration file for writing: %s"), strerror(errno));
315 fputs("# This file was generated by dolconf v" VERSION "\n\n", cf);
316 for(var = config; var->name != NULL; var++) {
317 fprintf(cf, "set %s ", var->name);
318 if((buf = quoteword(var->val)) == NULL) {
326 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
330 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, 0, &buf2, -1);
331 if((buf = quoteword(buf2)) == NULL) {
339 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, 1, &buf2, -1);
340 if((buf = quoteword(buf2)) == NULL) {
348 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
353 void astcancel(GtkWidget *widget, gpointer uudata)
358 #define bufcats(buf, str) bufcat(buf, str, strlen(str))
360 void astupdate(GtkWidget *widget, GtkWidget *page, gpointer uudata)
367 setcfvar("cli.defnick", gtk_entry_get_text(GTK_ENTRY(ast_nick)));
368 setcfvar("dc.desc", gtk_entry_get_text(GTK_ENTRY(ast_desc)));
371 for(var = config; var->name != NULL; var++) {
372 if(var->rname == NULL)
374 bufcats(s, var->rname);
376 bufcat(s, var->val, strlen(var->val));
379 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
381 bufcats(s, _("Shares:\n"));
384 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, 1, &buf, -1);
388 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
390 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(ast_summary)), s, sdata);
394 void cb_ast_wnd_apply(GtkWidget *widget, gpointer uudata)
400 void cb_ast_nick_changed(GtkWidget *widget, gpointer uudata)
402 if(v_dcstring(gtk_entry_get_text(GTK_ENTRY(ast_nick))))
403 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page1, TRUE);
405 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page1, FALSE);
408 int hasshare(int col, char *name)
413 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(shares), &iter)) {
415 gtk_tree_model_get(GTK_TREE_MODEL(shares), &iter, col, &buf, -1);
416 if(!strcmp(buf, name)) {
421 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(shares), &iter));
426 void cb_ast_shareadd_clicked(GtkWidget *widget, gpointer uudata)
435 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);
436 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(chd), TRUE);
437 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chd), TRUE);
438 resp = gtk_dialog_run(GTK_DIALOG(chd));
439 if(resp != GTK_RESPONSE_ACCEPT) {
440 gtk_widget_destroy(chd);
443 fns = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chd));
444 gtk_widget_destroy(chd);
447 if(!hasshare(1, fn)) {
448 if((p = strrchr(fn, '/')) == NULL)
453 if(hasshare(0, sn)) {
456 sn = sprintf2("%s%i", p, i);
461 gtk_list_store_append(shares, &iter);
462 gtk_list_store_set(shares, &iter, 0, sn, 1, fn, -1);
464 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page2, TRUE);
473 void cb_ast_sharerem_clicked(GtkWidget *widget, gpointer uudata)
477 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(ast_sharelist)), NULL, &iter))
478 gtk_list_store_remove(shares, &iter);
479 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(shares), NULL) == 0)
480 gtk_assistant_set_page_complete(GTK_ASSISTANT(ast_wnd), ast_page2, FALSE);
483 int main(int argc, char **argv)
487 setlocale(LC_ALL, "");
488 bindtextdomain(PACKAGE, LOCALEDIR);
492 gtk_init(&argc, &argv);
494 shares = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
495 gtk_tree_view_set_model(GTK_TREE_VIEW(ast_sharelist), GTK_TREE_MODEL(shares));
498 if(getenv("HOME") != NULL) {
499 cfname = sprintf2("%s/.doldacond.conf", getenv("HOME"));
501 if((pwd = getpwuid(getuid())) != NULL)
502 cfname = sprintf2("%s/.doldacond.conf", pwd->pw_dir);
505 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not get your home directory!"));
509 if(access(cfname, F_OK)) {
510 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) {
511 gtk_window_set_default_size(GTK_WINDOW(ast_wnd), 500, 350);
512 gtk_widget_show(ast_wnd);
515 if(readconfig() == 1) {
516 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)