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