chiark / gitweb /
65ef1f99ab655294d4d3d8772a75caedd5d04388
[sympathy.git] / apps / sympathyd.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[] =
10   "$Id$";
11
12 /*
13  * $Log$
14  * Revision 1.13  2008/02/15 23:52:12  james
15  * *** empty log message ***
16  *
17  * Revision 1.12  2008/02/15 03:32:07  james
18  * *** empty log message ***
19  *
20  * Revision 1.11  2008/02/14 16:21:17  james
21  * *** empty log message ***
22  *
23  * Revision 1.10  2008/02/14 10:39:14  james
24  * *** empty log message ***
25  *
26  * Revision 1.9  2008/02/14 10:34:47  james
27  * *** empty log message ***
28  *
29  * Revision 1.8  2008/02/14 10:34:30  james
30  * *** empty log message ***
31  *
32  * Revision 1.7  2008/02/14 02:46:44  james
33  * *** empty log message ***
34  *
35  * Revision 1.6  2008/02/14 00:57:58  james
36  * *** empty log message ***
37  *
38  * Revision 1.5  2008/02/13 18:05:06  james
39  * *** empty log message ***
40  *
41  * Revision 1.4  2008/02/13 17:21:55  james
42  * *** empty log message ***
43  *
44  * Revision 1.3  2008/02/08 15:06:52  james
45  * *** empty log message ***
46  *
47  * Revision 1.2  2008/02/07 15:42:49  james
48  * *** empty log message ***
49  *
50  * Revision 1.1  2008/02/05 14:25:49  james
51  * *** empty log message ***
52  *
53  */
54
55 #include <sys/time.h>
56 #include <sympathy.h>
57
58 #include "client.h"
59 #include "clients.h"
60
61 typedef struct
62 {
63   int nclients;
64   int lines;
65   int baud;
66   int crtscts;
67   int cd_edge_sec;
68   int blocked;
69   int bootstrap;
70 } Status;
71
72 static Status
73 get_status (TTY * t, Clients * cs)
74 {
75   static struct timeval last_cd_edge = { 0 };
76   static int last_cd_state = -1;
77   int cd;
78   struct timeval now, dif;
79
80   TTY_Status tty_status = { 0 };
81   Status status;
82
83   tty_get_status (t, &tty_status);
84
85   status.bootstrap = 1;
86   status.nclients = cs->n;
87   status.lines = tty_status.lines;
88   status.baud = tty_status.baud;
89   status.crtscts = (tty_status.termios.c_cflag & CRTSCTS) ? 1 : 0;
90   status.blocked = tty_status.blocked;
91
92   cd = (tty_status.lines & TIOCM_CD) ? 1 : 0;
93
94   if (cd != last_cd_state)
95     {
96       gettimeofday (&last_cd_edge, NULL);
97       last_cd_state = cd;
98     }
99
100   gettimeofday (&now, NULL);
101   timersub (&now, &last_cd_edge, &dif);
102   status.cd_edge_sec = dif.tv_sec;
103
104   return status;
105 }
106
107 static char *
108 line_to_name (int l)
109 {
110
111   switch (l)
112     {
113 #ifdef TIOCM_LE
114     case TIOCM_LE:
115       return "LE";
116 #endif
117 #ifdef TIOCM_DTR
118     case TIOCM_DTR:
119       return "DTR";
120 #endif
121 #ifdef TIOCM_RTS
122     case TIOCM_RTS:
123       return "RTS";
124 #endif
125 #ifdef TIOCM_ST
126     case TIOCM_ST:
127       return "ST";
128 #endif
129 #ifdef TIOCM_SR
130     case TIOCM_SR:
131       return "SR";
132 #endif
133 #ifdef TIOCM_CTS
134     case TIOCM_CTS:
135       return "CTS";
136 #endif
137 #ifdef TIOCM_CD
138     case TIOCM_CD:
139       return "CD";
140 #endif
141 #ifdef TIOCM_RI
142     case TIOCM_RI:
143       return "RI";
144 #endif
145 #ifdef TIOCM_DSR
146     case TIOCM_DSR:
147       return "DSR";
148 #endif
149     }
150   return "??";
151 }
152
153 static void
154 log_line_changes (Context * ctx, int old, int new)
155 {
156   int dif = old ^ new;
157   int c = 1;
158   char buf[1024], *ptr = buf;
159   char *n;
160
161   if (!dif)
162     return;
163   if (!ctx->l)
164     return;
165
166   n = "<Modem lines changed:";
167
168   while (*n)
169     *(ptr++) = *(n++);
170
171   while (dif >= c)
172     {
173
174       if (dif & c)
175         {
176           *(ptr++) = ' ';
177           *(ptr++) = (new & c) ? '+' : '-';
178           n = line_to_name (c);
179           while (*n)
180             *(ptr++) = *(n++);
181         }
182
183       c <<= 1;
184     }
185   *(ptr++) = '>';
186   *ptr = 0;
187
188
189   ctx->l->log (ctx->l, buf);
190
191 }
192
193 static char *
194 do_line (char *ptr, int lines, int line)
195 {
196   char *lname;
197
198   if (!(lines & line))
199     return ptr;
200   lname = line_to_name (line);
201
202   *(ptr++) = ' ';
203   while (*lname)
204     *(ptr++) = *(lname++);
205
206   return ptr;
207 }
208
209
210
211 static void
212 check_status (Context * c, Clients * cs)
213 {
214   static Status old_status = { 0 };
215   Status status;
216   char buf[1024];
217   char *ptr = buf;
218   char *t;
219
220   status = get_status (c->t, cs);
221   if (!memcmp (&status, &old_status, sizeof (status)))
222     return;
223   old_status = status;
224
225
226   log_line_changes (c, old_status.lines, status.lines);
227
228   ptr += sprintf (ptr, "CTRL-B ");
229
230   t = c->t->name;
231   if (!strncmp (t, "/dev/", 5))
232     t += 5;
233   while (*t)
234     *(ptr++) = *(t++);
235
236   ptr += sprintf (ptr, " %db", status.baud);
237
238   ptr = do_line (ptr, status.lines, TIOCM_RTS);
239   ptr = do_line (ptr, status.lines, TIOCM_CTS);
240   ptr = do_line (ptr, status.lines, TIOCM_DTR);
241   ptr = do_line (ptr, status.lines, TIOCM_DSR);
242   ptr = do_line (ptr, status.lines, TIOCM_RI);
243   ptr = do_line (ptr, status.lines, TIOCM_CD);
244
245   if (status.blocked)
246     {
247       t = ", Locked";
248       while (*t)
249         *(ptr++) = *(t++);
250     }
251
252   if (status.crtscts)
253     {
254       t = ", Flow";
255       while (*t)
256         *(ptr++) = *(t++);
257     }
258
259 #if 0
260   if (status.lines & TIOCM_CD)
261     {
262       ptr +=
263         sprintf (ptr, ", On %d.%d", status.cd_edge_sec / 60,
264                  status.cd_edge_sec % 60);
265     }
266   else
267     {
268       ptr +=
269         sprintf (ptr, ", Off %d.%d", status.cd_edge_sec / 60,
270                  status.cd_edge_sec % 60);
271     }
272 #endif
273
274   ptr +=
275     sprintf (ptr, ", %d client%s", status.nclients,
276              (status.nclients == 1) ? "" : "s");
277
278   *ptr = 0;
279
280   send_status (cs, buf);
281 }
282
283 int
284 main (int argc, char *argv[])
285 {
286   fd_set rfds, wfds;
287   Context c;
288   Socket *s, *cs;
289   Clients *clients;
290
291
292 #if 0
293   construct_possible_lock_files ("/dev/modem");
294   return 0;
295 #endif
296
297   s = socket_listen ("socket");
298
299 // c.t = ptty_open (NULL, NULL);
300   c.t = serial_open ("/dev/cellmodem", 0);
301   c.v = vt102_new ();
302   c.h = history_new (200);
303   c.l = file_log_new ("log");
304   c.k = keydis_vt102_new ();
305   c.d = NULL;
306
307
308   clients = clients_new ();
309
310   for (;;)
311     {
312       struct timeval tv = { 1, 0 };
313
314       check_status (&c, clients);
315
316       FD_ZERO (&rfds);
317       FD_ZERO (&wfds);
318
319       tty_pre_select (c.t, &rfds, &wfds);
320
321       FD_SET (s->fd, &rfds);
322
323       socket_pre_select (s, &rfds, &wfds);
324
325       clients_pre_select (clients, &rfds, &wfds);
326
327       select (FD_SETSIZE, &rfds, &wfds, NULL, &tv);
328
329       if (FD_ISSET (s->fd, &rfds) && ((cs = socket_accept (s))))
330         {
331           {
332             Client *cl;
333             /*New client connexion */
334             cl = clients_new_client (clients, cs, &c);
335
336             send_history (c.h, cl);
337             send_vt102 (c.v, cl);
338
339           }
340         }
341
342
343       clients_post_select (clients, &c, &rfds, &wfds);
344
345       if (FD_ISSET (c.t->rfd, &rfds))
346         {
347           char buf[IPC_MAX_BUF];
348           int red;
349
350           red = c.t->recv (c.t, buf, sizeof (buf));
351
352           if (red < 0)
353             break;
354
355           if (red)
356             {
357               send_output (clients, buf, red);
358               vt102_parse (&c, buf, red);
359             }
360         }
361
362
363
364     }
365
366   clients_shutdown (clients);
367   terminal_atexit ();
368   printf ("QUAT\n");
369 }