chiark / gitweb /
make login window a transient of the toplevel
[disorder] / disobedience / login.c
1 /*
2  * This file is part of DisOrder
3  * Copyright (C) 2007 Richard Kettlewell
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, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * 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
18  * USA
19  */
20 /** @file disobedience/login.c
21  * @brief Login box for Disobedience
22  */
23
24 #include "disobedience.h"
25 #include "split.h"
26 #include "filepart.h"
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30
31 /** @brief One field in the login window */
32 struct login_window_item {
33   /** @brief Description label */
34   const char *description;
35
36   /** @brief Return the current value */
37   const char *(*get)(void);
38
39   /** @brief Set a new value */
40   void (*set)(const char *value);
41
42   /** @brief Flags
43    * 
44    * - @ref LWI_HIDDEN - this is a password
45    */
46   unsigned flags;
47
48 };
49
50 /** @brief This is a password */
51 #define LWI_HIDDEN 0x0001
52
53 /** @brief Current login window */
54 static GtkWidget *login_window;
55
56 /** @brief Set connection defaults */
57 static void default_connect(void) {
58   if(!config->connect.n) {
59     config->connect.n = 2;
60     config->connect.s = xcalloc(2, sizeof (char *));
61     config->connect.s[0] = xstrdup("localhost");
62     config->connect.s[1] = xstrdup("9999"); /* whatever */
63   }
64 }
65
66 static const char *get_hostname(void) { return config->connect.s[0]; }
67 static const char *get_service(void) { return config->connect.s[1]; }
68 static const char *get_username(void) { return config->username; }
69 static const char *get_password(void) { return config->password; }
70
71 static void set_hostname(const char *s) { config->connect.s[0] = (char *)s; }
72 static void set_service(const char *s) { config->connect.s[1] = (char *)s; }
73 static void set_username(const char *s) { config->username = s; }
74 static void set_password(const char *s) { config->password = s; }
75
76 /** @brief Table used to generate the form */
77 static const struct login_window_item lwis[] = {
78   { "Hostname", get_hostname, set_hostname, 0 },
79   { "Service", get_service, set_service, 0 },
80   { "User name", get_username, set_username, 0 },
81   { "Password", get_password, set_password, LWI_HIDDEN },
82 };
83 #define NLWIS (sizeof lwis / sizeof *lwis)
84
85 static GtkWidget *lwi_entry[NLWIS];
86
87 static void update_config(void) {
88   size_t n;
89
90   for(n = 0; n < NLWIS; ++n)
91     lwis[n].set(xstrdup(gtk_entry_get_text(GTK_ENTRY(lwi_entry[n]))));
92 }
93
94 #if 0
95 static int modified_config(void) {
96   size_t n;
97
98   for(n = 0; n < NLWIS; ++n) {
99     const char *entered = gtk_entry_get_text(GTK_ENTRY(lwi_entry[n]));
100     const char *current = lwis[n].get();
101     if(strcmp(entered, current))
102       return 1;
103   }
104   return 0;
105 }
106 #endif
107
108 static void login_ok(GtkButton attribute((unused)) *button,
109                      gpointer attribute((unused)) userdata) {
110   update_config();
111   reset();
112 }
113
114 static void login_save(GtkButton attribute((unused)) *button,
115                        gpointer attribute((unused)) userdata) {
116   char *path = config_userconf(0, 0), *tmp;
117   FILE *fp;
118   GtkWidget *yorn = 0;
119
120   update_config();
121   /* See if the file already exists */
122   if(access(path, F_OK) == 0) {
123     yorn = gtk_message_dialog_new
124       (GTK_WINDOW(login_window),
125        GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
126        GTK_MESSAGE_QUESTION,
127        GTK_BUTTONS_NONE,
128        "File %s already exists", path);
129     gtk_dialog_add_buttons(GTK_DIALOG(yorn),
130                            "Overwrite", GTK_RESPONSE_ACCEPT,
131                            "Cancel", GTK_RESPONSE_REJECT,
132                            (char *)0);
133     if(gtk_dialog_run(GTK_DIALOG(yorn)) != GTK_RESPONSE_ACCEPT)
134       goto done;
135     gtk_widget_destroy(yorn);
136     yorn = 0;
137   }
138   byte_xasprintf(&tmp, "%s.tmp", path);
139   /* Make sure the directory exists; don't care if it already exists. */
140   mkdir(d_dirname(tmp), 02700);
141   /* Write out the file */
142   if(!(fp = fopen(tmp, "w"))) {
143     fpopup_msg(GTK_MESSAGE_ERROR, "error opening %s: %s",
144                tmp, strerror(errno));
145     goto done;
146   }
147   if(fprintf(fp, "username %s\n"
148              "password %s\n"
149              "connect %s %s\n",
150              quoteutf8(config->username),
151              quoteutf8(config->password),
152              quoteutf8(config->connect.s[0]),
153              quoteutf8(config->connect.s[1])) < 0) {
154     fpopup_msg(GTK_MESSAGE_ERROR, "error writing to %s: %s",
155                tmp, strerror(errno));
156     fclose(fp);
157     goto done;
158   }
159   if(fclose(fp) < 0) {
160     fpopup_msg(GTK_MESSAGE_ERROR, "error closing %s: %s",
161                tmp, strerror(errno));
162     goto done;
163   }
164   /* Rename into place */
165   if(rename(tmp, path) < 0) {
166     fpopup_msg(GTK_MESSAGE_ERROR, "error renaming %s: %s",
167                tmp, strerror(errno));
168     goto done;
169   }
170   fpopup_msg(GTK_MESSAGE_INFO, "Saved login configuration to %s", path);
171   gtk_widget_destroy(login_window);
172 done:
173   if(yorn)
174     gtk_widget_destroy(yorn);
175 }
176
177 static void login_cancel(GtkButton attribute((unused)) *button,
178                          gpointer attribute((unused)) userdata) {
179   gtk_widget_destroy(login_window);
180 }
181
182 /* Buttons that appear at the bottom of the window */
183 static const struct button buttons[] = {
184   {
185     "Login",
186     login_ok,
187     "Login with these settings",
188   },
189   {
190     GTK_STOCK_SAVE,
191     login_save,
192     "Save these settings",
193   },
194   {
195     GTK_STOCK_CANCEL,
196     login_cancel,
197     "Discard all changes and close window"
198   },
199 };
200
201 #define NBUTTONS (int)(sizeof buttons / sizeof *buttons)
202
203 /** @brief Pop up a login box */
204 void login_box(void) {
205   GtkWidget *table, *label, *entry,  *buttonbox, *vbox;
206   size_t n;
207
208   /* If there's one already then bring it to the front */
209   if(login_window) {
210     gtk_window_present(GTK_WINDOW(login_window));
211     return;
212   }
213   default_connect();
214   /* Create a new login window */
215   login_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
216   g_signal_connect(login_window, "destroy",
217                    G_CALLBACK(gtk_widget_destroyed), &login_window);
218   gtk_window_set_title(GTK_WINDOW(login_window), "Login Details");
219   /* Construct the form */
220   table = gtk_table_new(NLWIS + 1/*rows*/, 2/*columns*/, FALSE/*homogenous*/);
221   for(n = 0; n < NLWIS; ++n) {
222     label = gtk_label_new(lwis[n].description);
223     gtk_misc_set_alignment(GTK_MISC(label), 1/*right*/, 0/*bottom*/);
224     gtk_table_attach(GTK_TABLE(table), label,
225                      0, 1,              /* left/right_attach */
226                      n, n+1,            /* top/bottom_attach */
227                      GTK_FILL, 0,       /* x/yoptions */
228                      1, 1);             /* x/ypadding */
229     entry = gtk_entry_new();
230     gtk_entry_set_visibility(GTK_ENTRY(entry),
231                              lwis[n].flags & LWI_HIDDEN ? FALSE : TRUE);
232     gtk_entry_set_text(GTK_ENTRY(entry), lwis[n].get());
233     gtk_table_attach(GTK_TABLE(table), entry,
234                      1, 2,              /* left/right_attach */
235                      n, n+1,            /* top/bottom_attach */
236                      GTK_EXPAND|GTK_FILL, 0, /* x/yoptions */
237                      1, 1);             /* x/ypadding */
238     lwi_entry[n] = entry;
239   }
240   buttonbox = create_buttons(buttons, NBUTTONS);
241   vbox = gtk_vbox_new(FALSE, 1);
242   gtk_box_pack_start(GTK_BOX(vbox), table, 
243                      TRUE/*expand*/, TRUE/*fill*/, 1/*padding*/);
244   gtk_box_pack_start(GTK_BOX(vbox), buttonbox,
245                      FALSE/*expand*/, FALSE/*fill*/, 1/*padding*/);
246   gtk_container_add(GTK_CONTAINER(login_window), vbox);
247   gtk_window_set_transient_for(GTK_WINDOW(login_window),
248                                GTK_WINDOW(toplevel));
249   gtk_widget_show_all(login_window);
250 }
251
252 /*
253 Local Variables:
254 c-basic-offset:2
255 comment-column:40
256 fill-column:79
257 indent-tabs-mode:nil
258 End:
259 */