Use -l option to dolcon in gui-shell.
[doldaconnect.git] / clients / gui-shell / dsh.c
CommitLineData
34d45a15
FT
1/*
2 * Dolda Connect - Modular multiuser Direct Connect-style client
3 * Copyright (C) 2007 Fredrik Tolf <fredrik@dolda2000.com>
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 <errno.h>
25#include <pwd.h>
26#include <locale.h>
27#include <libintl.h>
28#include <signal.h>
29#include <sys/wait.h>
30#include <gtk/gtk.h>
31#include <gdk/gdkkeysyms.h>
32#include <stdarg.h>
33#include <doldaconnect/uilib.h>
34#include <doldaconnect/uimisc.h>
35#include <doldaconnect/utils.h>
36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40
41#ifdef HAVE_NOTIFY
42#include <libnotify/notify.h>
43#endif
44
45#define _(text) gettext(text)
46
47struct trinfo {
48 int ostate;
49};
50
51void updatewrite(void);
52
53GtkStatusIcon *tray;
54pid_t dpid = 0, dcpid = 0;
55int connected = 0;
56int dstat;
57int derrfd, derrtag;
58char *derrbuf = NULL;
59size_t derrbufsize = 0, derrbufdata = 0;
60int dcfd, dcfdrtag, dcfdwtag = -1;
61GdkPixbuf *dcicon;
62#ifdef HAVE_NOTIFY
63NotifyNotification *trnote = NULL;
64#endif
65
66#include "dsh-start.gtkh"
67#include "dsh-menu.gtkh"
68
69int running(char *pf)
70{
71 FILE *pfs;
72 char buf[1024];
73 int pid;
74
75 if((pfs = fopen(pf, "r")) == NULL) {
76 perror(pf);
77 return(0);
78 }
79 fgets(buf, sizeof(buf), pfs);
80 fclose(pfs);
81 if((pid = atoi(buf)) == 0)
82 return(0);
83 return(!kill(pid, 0));
84}
85
86void derrcb(gpointer data, gint source, GdkInputCondition cond)
87{
88 int ret = 0;
89
90 sizebuf2(derrbuf, derrbufdata + 1024, 1);
91 ret = read(derrfd, derrbuf + derrbufdata, derrbufsize - derrbufdata);
92 if(ret <= 0) {
93 if(ret < 0)
94 bprintf(derrbuf, "\ncould not read from daemon: %s\n", strerror(errno));
95 gdk_input_remove(derrtag);
96 close(derrfd);
97 derrfd = -1;
98 } else {
99 derrbufdata += ret;
100 }
101}
102
103int msgbox(int type, int buttons, char *format, ...)
104{
105 GtkWidget *swnd;
106 va_list args;
107 char *buf;
108 int resp;
109
110 va_start(args, format);
111 buf = vsprintf2(format, args);
112 va_end(args);
113 swnd = gtk_message_dialog_new(NULL, 0, type, buttons, "%s", buf);
114 resp = gtk_dialog_run(GTK_DIALOG(swnd));
115 gtk_widget_destroy(swnd);
116 free(buf);
117 return(resp);
118}
119
120void destroytr(struct dc_transfer *tr)
121{
122 struct trinfo *tri;
123
124 tri = tr->udata;
125 free(tri);
126}
127
128void inittr(struct dc_transfer *tr)
129{
130 struct trinfo *tri;
131
132 tr->udata = tri = memset(smalloc(sizeof(*tri)), 0, sizeof(*tri));
133 tr->destroycb = destroytr;
134 tri->ostate = tr->state;
135}
136
137#ifdef HAVE_NOTIFY
138void notify(NotifyNotification **n, char *cat, char *title, char *body, ...)
139{
140 va_list args;
141 char *bbuf;
142
143 va_start(args, body);
144 bbuf = vsprintf2(body, args);
145 va_end(args);
146 if(*n == NULL) {
147 *n = notify_notification_new_with_status_icon(title, bbuf, NULL, tray);
148 notify_notification_set_icon_from_pixbuf(*n, dcicon);
149 } else {
150 notify_notification_update(*n, title, bbuf, NULL);
151 }
152 notify_notification_show(*n, NULL);
153}
154#endif
155
156void trstatechange(struct dc_transfer *tr, int ostate)
157{
158 if(ostate == DC_TRNS_MAIN) {
159 if(tr->state == DC_TRNS_DONE) {
160#ifdef HAVE_NOTIFY
161 notify(&trnote, "transfer.complete", _("Transfer complete"), _("Finished downloading %ls from %ls"), tr->path, tr->peernick);
162#endif
163 } else {
164#ifdef HAVE_NOTIFY
165 notify(&trnote, "transfer.error", _("Transfer interrupted"), _("The transfer of %ls from %ls was interrupted from the other side"), tr->path, tr->peernick);
166#endif
167 }
168 }
169}
170
171void updatetrinfo(void)
172{
173 struct dc_transfer *tr;
174 struct trinfo *tri;
175
176 for(tr = dc_transfers; tr != NULL; tr = tr->next) {
177 if(tr->udata == NULL) {
178 inittr(tr);
179 } else {
180 tri = tr->udata;
181 if(tri->ostate != tr->state) {
182 trstatechange(tr, tri->ostate);
183 tri->ostate = tr->state;
184 }
185 }
186 }
187}
188
189void trlscb(int resp, void *data)
190{
191 updatetrinfo();
192}
193
194void logincb(int err, wchar_t *reason, void *data)
195{
196 if(err != DC_LOGIN_ERR_SUCCESS) {
197 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server"));
198 exit(1);
199 }
200 gtk_status_icon_set_tooltip(tray, "Dolda Connect");
201 dc_queuecmd(NULL, NULL, L"notify", L"trans:act", L"on", L"trans:prog", L"on", NULL);
202 dc_gettrlistasync(trlscb, NULL);
203 connected = 1;
204 updatewrite();
205}
206
207void dcfdcb(gpointer data, gint source, GdkInputCondition cond)
208{
209 struct dc_response *resp;
210
211 if(((cond & GDK_INPUT_READ) && dc_handleread()) || ((cond & GDK_INPUT_WRITE) && dc_handlewrite())) {
212 if(errno == 0) {
213 gtk_main_quit();
214 } else {
215 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server: %s"), strerror(errno));
216 exit(1);
217 }
218 return;
219 }
220 while((resp = dc_getresp()) != NULL) {
221 if(!wcscmp(resp->cmdname, L".connect")) {
222 if(resp->code != 201) {
223 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The server refused the connection"));
224 exit(1);
225 } else if(dc_checkprotocol(resp, DC_LATEST)) {
226 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Server protocol revision mismatch"));
227 exit(1);
228 } else {
229 gtk_status_icon_set_tooltip(tray, _("Authenticating..."));
230 dc_loginasync(NULL, 1, dc_convnone, logincb, NULL);
231 }
232 } else if(!wcscmp(resp->cmdname, L".notify")) {
233 dc_uimisc_handlenotify(resp);
234 updatetrinfo();
235 }
236 }
237 updatewrite();
238}
239
240void updatewrite(void)
241{
242 if(dcfd < 0)
243 return;
244 if(dc_wantwrite()) {
245 if(dcfdwtag == -1)
246 dcfdwtag = gdk_input_add(dcfd, GDK_INPUT_WRITE, dcfdcb, NULL);
247 } else {
248 if(dcfdwtag != -1) {
249 gdk_input_remove(dcfdwtag);
250 dcfdwtag = -1;
251 }
252 }
253}
254
255void connectdc(void)
256{
257 if((dcfd = dc_connect(dc_srv_local)) < 0) {
258 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server: %s"), strerror(errno));
259 exit(1);
260 }
261 dcfdrtag = gdk_input_add(dcfd, GDK_INPUT_READ, dcfdcb, NULL);
262 updatewrite();
263 gtk_status_icon_set_tooltip(tray, _("Connecting to server..."));
264}
265
266void startdaemon(void)
267{
268 char pf[1024];
269 int pfd[2], i;
270
271 if(getenv("HOME") != NULL)
272 snprintf(pf, sizeof(pf), "%s/.doldacond.pid", getenv("HOME"));
273 else
274 snprintf(pf, sizeof(pf), "%s/.doldacond.pid", getpwuid(getuid())->pw_dir);
275 if(access(pf, F_OK) || !running(pf)) {
276 pipe(pfd);
277 if((dpid = fork()) == 0) {
278 dup2(pfd[1], 2);
279 for(i = 3; i < FD_SETSIZE; i++)
280 close(i);
281 execlp("doldacond", "doldacond", "-p", pf, NULL);
282 perror("doldacond");
283 exit(127);
284 }
285 if(dpid == -1)
286 abort();
287 close(pfd[1]);
288 derrfd = pfd[0];
289 derrtag = gdk_input_add(derrfd, GDK_INPUT_READ, derrcb, NULL);
290 create_start_wnd();
291 gtk_widget_show(start_wnd);
292 gtk_status_icon_set_tooltip(tray, _("Starting..."));
293 } else {
294 connectdc();
295 }
296}
297
298gboolean daemonized(gpointer uu)
299{
300 gtk_widget_hide(start_wnd);
301 dpid = 0;
302 if(derrfd != -1) {
303 gdk_input_remove(derrtag);
304 close(derrfd);
305 }
306 if(dstat != 0) {
307 gtk_status_icon_set_visible(tray, FALSE);
308 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(start_log)), derrbuf, derrbufdata);
309 gtk_widget_show(start_errwnd);
310 } else {
311 connectdc();
312 }
313 return(FALSE);
314}
315
316void sighandler(int sig)
317{
318 pid_t p;
319 int status;
320
321 if(sig == SIGCHLD) {
322 while((p = waitpid(-1, &status, WNOHANG)) > 0) {
323 if(p == dpid) {
324 dstat = status;
325 gtk_timeout_add(1, daemonized, NULL);
326 } else if(p == dcpid) {
327 dcpid = 0;
328 }
329 }
330 }
331}
332
333void dolcon(void)
334{
335 int i;
336
337 if((dcpid = fork()) == 0) {
338 for(i = 3; i < FD_SETSIZE; i++)
339 close(i);
c4aa9572 340 execlp("dolcon", "dolcon", "-l", NULL);
34d45a15
FT
341 perror("dolcon");
342 exit(127);
343 }
344}
345
346void cb_shm_dolcon_activate(GtkWidget *uu1, gpointer uu2)
347{
348 dolcon();
349}
350
351void cb_shm_quit_activate(GtkWidget *uu1, gpointer uu2)
352{
353 dc_queuecmd(NULL, NULL, L"shutdown", NULL);
354 updatewrite();
355}
356
357void tray_activate(GtkStatusIcon *uu1, gpointer uu2)
358{
359 if(dpid != 0) {
360 gtk_widget_show(start_wnd);
361 } else if(connected) {
362 dolcon();
363 }
364}
365
366void tray_popup(GtkStatusIcon *uu1, guint button, guint time, gpointer uu2)
367{
368 gtk_menu_popup(GTK_MENU(shm_menu), NULL, NULL, NULL, NULL, button, time);
369}
370
371void cb_start_hide_clicked(GtkWidget *uu1, gpointer uu2)
372{
373 gtk_widget_hide(start_wnd);
374}
375
376void cb_start_abort_clicked(GtkWidget *uu1, gpointer uu2)
377{
378 kill(dpid, SIGINT);
379 exit(0);
380}
381
382void cb_start_errok_clicked(GtkWidget *uu1, gpointer uu2)
383{
384 gtk_main_quit();
385}
386
387#include "../dolda-icon.xpm"
388
389void inittray(void)
390{
391 tray = gtk_status_icon_new_from_pixbuf(gdk_pixbuf_scale_simple(dcicon, 24, 24, GDK_INTERP_BILINEAR));
392 gtk_status_icon_set_tooltip(tray, "");
393 g_signal_connect(G_OBJECT(tray), "activate", G_CALLBACK(tray_activate), (gpointer)NULL);
394 g_signal_connect(G_OBJECT(tray), "popup-menu", G_CALLBACK(tray_popup), (gpointer)NULL);
395}
396
397int main(int argc, char **argv)
398{
399 setlocale(LC_ALL, "");
400 bindtextdomain(PACKAGE, LOCALEDIR);
401 textdomain(PACKAGE);
402 signal(SIGCHLD, sighandler);
403 dc_init();
404 gtk_init(&argc, &argv);
405#ifdef HAVE_NOTIFY
406 notify_init("Dolda Connect");
407#endif
408
409 create_shm_wnd();
410 dcicon = gdk_pixbuf_new_from_xpm_data((const char **)dolda_icon_xpm);
411 gtk_window_set_default_icon(dcicon);
412 inittray();
413 startdaemon();
414
415 gtk_main();
416
417 return(0);
418}
419
420#include "dsh-start.gtk"
421#include "dsh-menu.gtk"