chiark / gitweb /
*** empty log message ***
[sympathy.git] / apps / sympathy.c
1 /*
2  * sympathy.c:
3  *
4  * Copyright (c) 2008 James McKenzie <james@fishsoup.dhs.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] = "$Id$";
10
11 /*
12  * $Log$
13  * Revision 1.6  2008/02/20 17:18:33  james
14  * *** empty log message ***
15  *
16  * Revision 1.5  2008/02/20 15:50:14  james
17  * *** empty log message ***
18  *
19  * Revision 1.4  2008/02/20 02:11:35  james
20  * *** empty log message ***
21  *
22  * Revision 1.3  2008/02/14 02:46:44  james
23  * *** empty log message ***
24  *
25  * Revision 1.2  2008/02/14 00:57:58  james
26  * *** empty log message ***
27  *
28  * Revision 1.1  2008/02/05 14:25:49  james
29  * *** empty log message ***
30  *
31  */
32
33 #include <stdarg.h>
34 #include <sympathy.h>
35 #include "mainloop.h"
36
37 char *fatal_moan(char *fmt,...)
38 {
39 va_list ap;
40
41
42 va_start(ap, fmt);
43 n = vfprintf (stderr,fmt,ap);
44 va_end(ap);
45
46 putc('\n',stderr);
47 exit(1);
48 }
49
50
51
52 /*make the path in fmt from home (hence the name) */
53
54 char *mome(char *fmt,...)
55 {
56
57                  int n;
58                 int homelen;
59                  char *buf,*home;
60                  va_list ap;
61
62
63                 home=getenv("HOME");
64                 if (!home) return NULL;
65
66                 homelen=strlen(home)+1;
67
68                 size=1024+homelen;
69
70                 buf = malloc (size);
71
72                 if (!buf) 
73                         fatal_moan("malloc failed");
74
75                 strcpy(buf,home);
76                 strcat(buf,"/");
77
78                  while (1) {
79
80
81                     va_start(ap, fmt);
82                     n = vsnprintf (buf+homelen, size-homelen, fmt, ap);
83                     va_end(ap);
84
85                     if (n > -1 && n < len)
86                        return buf;
87
88                     if (n > -1)    /* glibc 2.1 */
89                        size = homelen+n+1; 
90                     else           /* glibc 2.0 */
91                        size *= 2;  /* twice the old size */
92                 
93                   buf=realloc(buf,size);
94
95                 if (!buf) 
96                         fatal_moan("malloc failed");
97                  }
98               }
99 }
100
101
102
103 int
104 main (int argc, char *argv[])
105 {
106   int c;
107   extern char *optarg;
108   extern int optind, opterr, optopt;
109
110   int oflags[128];
111   char *oargs[128];
112
113   Socket *server_socket = NULL, *client_socket = NULL;
114   ANSI *ansi = NULL;
115   TTY *tty = NULL;
116
117   memset (oflags[128], 0, sizeof (oflags));
118   memset (oargs[128], 0, sizeof (oargs));
119
120   while ((c = getopt (argc, argv, "tscr:d:pb:fL:Fk:n:")) != EOF)
121     {
122       switch (c)
123         {
124         case ':':
125         case 'h':
126         case '?':
127           usage ();
128         default:
129           if ((c > 64) && (c < 91))
130             {
131               oflags[c]++;
132               oargs[c] = optarg;
133             }
134           else if ((c > 96) && (c < 123))
135             {
136               oflags[c]++;
137               oargs[c] = optarg;
138             }
139           else
140             {
141               moan ("unknown option %c", c);
142               usage ();
143             }
144         }
145
146     }
147
148   if (!oflags['s'] && !oflags['c'] && !oflags['t'] && !oflags['r'])
149     {
150       /*If no mode is specified behave like screen */
151       oflags['s']++;
152       oflags['c']++;
153     }
154
155   if ((oflags['t'] && ((oflags['s'] || oflags['c']) || oflags['r'])) ||
156       (oflags['r'] && ((oflags['s'] || oflags['c']) || oflags['t'])) ||
157       ((oflags['s'] || oflags['c']) && (oflags['r'] || oflags['t'])))
158     fatal_moan ("specifiy exactly one of ( -c and or -s ), -t and -r");
159
160   if (oflags['r'] && oflags['k'])
161     fatal_moan ("-k is incompatible with -r");
162
163
164   /*Fold -r into -c */
165   if (oflags['r'])
166     {
167       int id = safe_atoi (oargs['r']);
168       if (id < 0)
169         fatal_moan ("cannot parse -r %s as an integer", oargs['r']);
170
171       oflags['k']++;
172       oargs['k'] = mome ("/.sympathy/%d", id);
173       oflags['r'] = 0;
174       oflags['c']++;
175     }
176
177   if (oflags['c'] && !oflags['k'])
178     fatal_moan ("-c requires a socket to be specified with -s or -k");
179
180   if (oflags['p'] && oflags['d'])
181     fatal_moan ("-p incompatible with -d");
182
183   /*implement server and client by opening the server socket to prevent */
184   /*a race condition, and then forking and munging the cmd line options */
185   /*in the parent and child so that the child is the server and the */
186   /*parent becomes its client */
187
188   if (oflags['c'] && oflags['s'] && oflags['F'])
189     fatal_moan ("-F is incompatible with -c -s");
190
191   if (oflags['s'] && !oflags['k'])
192     {
193       char *path;
194       path = mome ("/.sympathy");
195       mkdir (path, 0700);
196       free (path);
197
198       oargs['k'] = mome ("/.sympathy/%d", getpid ());
199       oflags['k']++;
200     }
201
202   if (oflags['s'])
203     {
204       server_socket = socket_listen (oargs['k']);
205       if (!server_socket)
206         fatal_moan ("failed to create socket %s for listening", oargs['k']);
207     }
208
209   switch (fork ())
210     {
211     case 0:                    /*child becomes the server */
212       oflags['c'] = 0;
213       oflags['H'] = 0;
214       break;
215     case -1:
216       fatal_moan ("fork failed");
217     default:
218       oflags['s'] = 0;
219       oflags['K'] = 0;
220       oflags['d'] = 0;
221       oflags['p'] = 0;
222       oflags['b'] = 0;
223       oflags['f'] = 0;
224       oflags['L'] = 0;
225       oflags['n'] = 0;
226     }
227
228
229   if ((oflags['p'] || oflags['d'] || oflags['K'] || oflags['b'] || oflags['f']
230        || oflags['L']) && oflags['c'])
231     fatal_moan ("-c or -r are incompatible with -p, -d, -K, -b, -f or -L");
232
233   if (oflags['t'] || oflags['s'])
234     {
235       if (!oflags['p'] && !oflags['d'])
236         oflags['p']++;
237     }
238
239
240   if (oflags['s'] || oflags['t'])
241     {
242
243       if (oflags['L'])
244         {
245           log = file_log_new (oargs['L']);
246           if (!log)
247             fatal_moan ("unable to access log file %s", oargs['L']);
248         }
249
250       if (oflags['p'])
251         {
252           tty = ptty_open (NULL, NULL);
253         }
254       else
255         {
256           tty =
257             serial_open (oargs['d'],
258                          oflags['K'] ? SERIAL_LOCK_ACTIVE :
259                          SERIAL_LOCK_PASSIVE);
260           if (tty)
261             fatal_moan ("unable to open serial port %s", oargs['d']);
262         }
263
264       if (oflags['b'])
265         {
266           int baud = safe_atoi (oargs['b']);
267
268           if (baud < 0)
269             fatal_maon ("Unable to parse baudrate %s", oargs['b']);
270
271           tty_set_baud (tty, baud);
272
273         }
274
275       tty_set_flow (tty, oflags['f'] ? 1 : 0);
276
277     }
278
279   if (oflags['c'])
280     {
281
282       client_socket = socket_connect (oargs['k']);
283       if (!client_socket)
284         fatal_moan ("failed to connect to socket %s", oargs['k']);
285
286
287     }
288
289   if (oflags['c'] || oflags['t'])
290     {
291
292       if (oflags['H'])
293         {
294           fatal_moan ("fix a bug in HTML dispatcher before this works");
295         }
296       else
297         {
298           ansi = (ANSI *) malloc (sizeof (ANSI));
299           memset (ansi, 0, sizeof (ANSI));
300
301           terminal_register_handlers ();
302           ansi->terminal = terminal_open (0, 1);
303           ansi_reset (ansi, NULL);
304         }
305     }
306
307   if (oflags['s'] && !oflags['F']) {
308                 /*FIXME become a daemon*/
309   }
310
311   mainloop (tty, server_socket, client_socket, ansi, log);
312
313   if (ansi)
314     {
315       ansi_terminal_reset (ansi);
316       terminal_atexit ();
317     }
318
319   return 0;
320 }