chiark / gitweb /
Install serialmgr and run_sympathy in examples directory (uncompressed)
[sympathy.git] / apps / clients.c
1 /* 
2  * clients.c:
3  *
4  * Copyright (c) 2008 James McKenzie <sympathy@madingley.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] = "$Id: clients.c,v 1.25 2008/05/09 12:35:57 james Exp $";
10
11 /* 
12  * $Log: clients.c,v $
13  * Revision 1.25  2008/05/09 12:35:57  james
14  * *** empty log message ***
15  *
16  * Revision 1.24  2008/03/11 17:56:04  james
17  * *** empty log message ***
18  *
19  * Revision 1.23  2008/03/11 17:47:24  james
20  * *** empty log message ***
21  *
22  * Revision 1.22  2008/03/07 14:16:44  james
23  * *** empty log message ***
24  *
25  * Revision 1.21  2008/03/07 14:13:40  james
26  * *** empty log message ***
27  *
28  * Revision 1.20  2008/03/07 13:56:39  james
29  * *** empty log message ***
30  *
31  * Revision 1.19  2008/03/07 13:16:02  james
32  * *** empty log message ***
33  *
34  * Revision 1.18  2008/03/03 18:16:16  james
35  * *** empty log message ***
36  *
37  * Revision 1.17  2008/03/03 18:15:19  james
38  * *** empty log message ***
39  *
40  * Revision 1.16  2008/03/03 06:04:42  james
41  * *** empty log message ***
42  *
43  * Revision 1.15  2008/03/02 10:27:24  james
44  * *** empty log message ***
45  *
46  * Revision 1.14  2008/02/28 16:57:51  james
47  * *** empty log message ***
48  *
49  * Revision 1.13  2008/02/28 16:37:16  james
50  * *** empty log message ***
51  *
52  * Revision 1.12  2008/02/28 12:12:24  james
53  * *** empty log message ***
54  *
55  * Revision 1.11  2008/02/23 11:48:51  james
56  * *** empty log message ***
57  *
58  * Revision 1.10  2008/02/22 17:06:59  james
59  * *** empty log message ***
60  *
61  * Revision 1.9  2008/02/20 18:49:11  staffcvs
62  * *** empty log message ***
63  *
64  * Revision 1.8  2008/02/20 18:31:44  james
65  * *** empty log message ***
66  *
67  * Revision 1.7  2008/02/15 23:52:12  james
68  * *** empty log message ***
69  *
70  * Revision 1.6  2008/02/15 03:32:07  james
71  * *** empty log message ***
72  *
73  * Revision 1.5  2008/02/14 10:34:47  james
74  * *** empty log message ***
75  *
76  * Revision 1.4  2008/02/14 10:34:30  james
77  * *** empty log message ***
78  *
79  * Revision 1.3  2008/02/14 02:46:44  james
80  * *** empty log message ***
81  *
82  * Revision 1.2  2008/02/14 00:57:58  james
83  * *** empty log message ***
84  *
85  * Revision 1.1  2008/02/13 18:05:06  james
86  * *** empty log message ***
87  *
88  */
89
90 #include <sympathy.h>
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #include <strings.h>
95 #include <malloc.h>
96 #include "clients.h"
97
98
99 void
100 client_initialize (Client * c, Context * ctx)
101 {
102   send_history (ctx->h, c);
103   send_vt102 (ctx->v, c);
104   c->initialized = 1;
105 }
106
107 void
108 client_execute_message (Client * client, IPC_Msg * m, Context * c)
109 {
110   switch (m->hdr.type)
111     {
112     case IPC_MSG_TYPE_NOOP:
113       break;
114     case IPC_MSG_TYPE_DEBUG:
115       log_f (c->l, "<debug message %s>", m->debug.msg);
116       break;
117     case IPC_MSG_TYPE_KEY:
118       vt102_send (c, m->key.key);
119       break;
120     case IPC_MSG_TYPE_SETBAUD:
121       tty_set_baud (c->t, m->setbaud.baud);
122       tty_parse_reset (c);
123       log_f (c->l, "<baud changed to %d>", m->setbaud.baud);
124       break;
125     case IPC_MSG_TYPE_SENDBREAK:
126       log_f (c->l, "<break sent>");
127       tty_send_break (c->t);
128       break;
129     case IPC_MSG_TYPE_SETFLOW:
130       log_f (c->l, "<flow control turned %s>",
131              m->setflow.flow ? "on" : "off");
132       tty_set_flow (c->t, m->setflow.flow);
133       break;
134     case IPC_MSG_TYPE_SETANSI:
135       vt102_set_ansi (c->v, m->setansi.ansi);
136       break;
137     case IPC_MSG_TYPE_HANGUP:
138       log_f (c->l, "<hangup initiated>");
139       tty_hangup (c->t);
140       break;
141     case IPC_MSG_TYPE_SETSIZE:
142       vt102_resize (c, m->setsize.winsize);
143       break;
144     case IPC_MSG_TYPE_RESET:
145       vt102_reset (c);
146       break;
147     case IPC_MSG_TYPE_INITIALIZE:
148       client_initialize (client, c);
149       break;
150     case IPC_MSG_TYPE_KILLME:
151       client->dead++;
152       break;
153
154     default:
155       log_f (c->l, "<Unhandled message type %d>", m->hdr.type);
156     }
157 }
158
159
160 void
161 client_free (Client * c)
162 {
163   if (c->s)
164     socket_free (c->s);
165
166   free (c);
167 #if 0
168   fprintf (stderr, "Client at %p freed\n", c);
169 #endif
170 }
171
172 Client *
173 clients_new_client (Clients * cs, Socket * s, Context * ctx)
174 {
175   Client *c;
176
177   c = (Client *) xmalloc (sizeof (Client));
178
179   c->initialized = 0;
180   c->dead = 0;
181   c->s = s;
182   c->next = cs->head;
183
184   cs->head = c;
185   cs->n++;
186
187 #if 0
188   fprintf (stderr, "Client at %p created\n", c);
189 #endif
190
191   log_f (ctx->l, "<client %p connected - now %d clients>", c, cs->n);
192
193   if (ipc_msg_send_debug (s, "new_client"))
194     c->dead++;
195
196   return c;
197 }
198
199 void
200 clients_reap (Clients * cs, Context * ctx)
201 {
202   Client **p, *c;
203
204
205   for (p = &cs->head; *p;)
206     {
207       Client *c = *p;
208
209       if (c->dead)
210         {
211           *p = c->next;
212           client_free (c);
213           cs->n--;
214           log_f (ctx->l, "<client %p disconnected - now %d clients>", c,
215                  cs->n);
216         }
217       else
218         {
219           p = &(c->next);
220         }
221     }
222 }
223
224 Clients *
225 clients_new (void)
226 {
227   Clients *ret = (Clients *) xmalloc (sizeof (Clients));
228
229   ret->n = 0;
230   ret->head = NULL;
231
232   return ret;
233 }
234
235 void
236 clients_pre_select (Clients * cs, fd_set * rfds, fd_set * wfds)
237 {
238   Client *c;
239
240   for (c = cs->head; c; c = c->next)
241     {
242       socket_pre_select (c->s, rfds, wfds);
243     }
244 }
245
246 void
247 clients_post_select (Clients * cs, Context * ctx, fd_set * rfds,
248                      fd_set * wfds)
249 {
250   Client *c;
251   int deaded = 0;
252
253   for (c = cs->head; c; c = c->next)
254     {
255       if (socket_post_select (c->s, rfds, wfds))
256         {
257           c->dead++;
258           deaded++;
259         }
260
261       if (c->s->msg)
262         {
263           client_execute_message (c, c->s->msg, ctx);
264           socket_consume_msg (c->s);
265           if (c->dead)
266             deaded++;
267         }
268
269     }
270
271   if (deaded)
272     clients_reap (cs, ctx);
273 }
274
275
276 void
277 clients_shutdown (Clients * cs, Context * ctx)
278 {
279   Client *c;
280
281   for (c = cs->head; c; c = c->next)
282     {
283       c->dead++;
284     }
285
286
287   clients_reap (cs, ctx);
288 }
289
290
291
292
293
294
295 int
296 send_status (Clients * cs, char *msg)
297 {
298   char mbuf[IPC_MAX_BUF + sizeof (IPC_Msg_status)];
299   IPC_Msg_status *m = (IPC_Msg_status *) mbuf;
300   int len;
301
302   Client *c;
303
304   if (!msg)
305     return;
306   len = strlen (msg) + 1;
307
308   if (!len)
309     return;
310   if (len > IPC_MAX_BUF)
311     len = IPC_MAX_BUF;
312
313   m->size = len + sizeof (IPC_Msg_status);
314   m->type = IPC_MSG_TYPE_STATUS;
315   strncpy (m->status, msg, IPC_MAX_BUF);
316   m->status[IPC_MAX_BUF - 1] = 0;
317
318   for (c = cs->head; c; c = c->next)
319     {
320       if (!c->dead && c->initialized)
321         if (ipc_msg_send (c->s, (IPC_Msg *) m))
322           c->dead++;
323     }
324
325   return len;
326 }
327
328
329 int
330 send_output (Clients * cs, void *buf, int len)
331 {
332   char mbuf[IPC_MAX_BUF + sizeof (IPC_Msg_term)];
333   IPC_Msg_term *m = (IPC_Msg_term *) mbuf;
334
335   Client *c;
336
337   if (!len)
338     return;
339   if (len > IPC_MAX_BUF)
340     len = IPC_MAX_BUF;
341
342   m->size = len + sizeof (IPC_Msg_term);
343   m->type = IPC_MSG_TYPE_TERM;
344   m->len = len;
345   memcpy (m->term, buf, len);
346
347   for (c = cs->head; c; c = c->next)
348     {
349       if (!c->dead && c->initialized)
350         if (ipc_msg_send (c->s, (IPC_Msg *) m))
351           c->dead++;
352     }
353
354
355   return len;
356 }
357
358 void
359 send_history (History * h, Client * c)
360 {
361   int rptr = h->wptr;
362
363   HISTORY_INC (h, rptr);
364
365   HISTORY_INC (h, rptr);
366   while (rptr != h->wptr)
367     {
368       History_ent *l = &h->lines[rptr];
369       if (l->valid)
370         {
371
372           if (ipc_msg_send_history (c->s, l))
373             c->dead++;
374
375         }
376       HISTORY_INC (h, rptr);
377     }
378 }
379
380 void
381 send_vt102 (VT102 * v, Client * c)
382 {
383   if (ipc_msg_send_vt102 (c->s, v))
384     c->dead++;
385
386 }