chiark / gitweb /
serialmgr: Look for things in /usr, not /usr/local
[sympathy.git] / apps / sympathy.c
1 /* 
2  * sympathy.c:
3  *
4  * Copyright (c) 2008 James McKenzie <sympathy@madingley.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] =
10   "$Id: sympathy.c,v 1.52 2010/07/27 14:49:34 james Exp $";
11
12 /* 
13  * $Log: sympathy.c,v $
14  * Revision 1.52  2010/07/27 14:49:34  james
15  * add support for byte logging
16  *
17  * Revision 1.51  2010/07/16 11:04:10  james
18  * ignore tedious return values
19  *
20  * Revision 1.50  2008/05/09 12:56:28  staffcvs
21  * *** empty log message ***
22  *
23  * Revision 1.49  2008/05/09 12:43:49  staffcvs
24  * *** empty log message ***
25  *
26  * Revision 1.48  2008/05/09 12:35:57  james
27  * *** empty log message ***
28  *
29  * Revision 1.47  2008/05/09 12:26:58  staffcvs
30  * *** empty log message ***
31  *
32  * Revision 1.46  2008/05/09 12:19:18  james
33  * *** empty log message ***
34  *
35  * Revision 1.45  2008/03/15 01:44:31  james
36  * *** empty log message ***
37  *
38  * Revision 1.44  2008/03/12 01:30:23  james
39  * *** empty log message ***
40  *
41  * Revision 1.43  2008/03/12 01:26:56  james
42  * *** empty log message ***
43  *
44  * Revision 1.42  2008/03/11 15:02:52  james
45  * *** empty log message ***
46  *
47  * Revision 1.41  2008/03/10 11:49:32  james
48  * *** empty log message ***
49  *
50  * Revision 1.40  2008/03/07 14:16:44  james
51  * *** empty log message ***
52  *
53  * Revision 1.39  2008/03/07 14:13:40  james
54  * *** empty log message ***
55  *
56  * Revision 1.38  2008/03/07 13:56:39  james
57  * *** empty log message ***
58  *
59  * Revision 1.37  2008/03/07 13:16:02  james
60  * *** empty log message ***
61  *
62  * Revision 1.36  2008/03/06 21:34:09  james
63  * *** empty log message ***
64  *
65  * Revision 1.35  2008/03/06 21:33:02  james
66  * *** empty log message ***
67  *
68  * Revision 1.34  2008/03/06 16:49:39  james
69  * *** empty log message ***
70  *
71  * Revision 1.33  2008/03/06 16:49:05  james
72  * *** empty log message ***
73  *
74  * Revision 1.32  2008/03/03 06:04:42  james
75  * *** empty log message ***
76  *
77  * Revision 1.31  2008/03/03 06:04:18  james
78  * *** empty log message ***
79  *
80  * Revision 1.30  2008/03/02 10:38:18  james
81  * *** empty log message ***
82  *
83  * Revision 1.29  2008/03/02 10:37:56  james
84  * *** empty log message ***
85  *
86  * Revision 1.28  2008/03/02 10:27:24  james
87  * *** empty log message ***
88  *
89  * Revision 1.27  2008/03/02 09:55:37  james
90  * *** empty log message ***
91  *
92  * Revision 1.26  2008/02/29 14:55:09  james
93  * *** empty log message ***
94  *
95  * Revision 1.25  2008/02/28 22:43:25  james
96  * *** empty log message ***
97  *
98  * Revision 1.24  2008/02/28 22:00:42  james
99  * *** empty log message ***
100  *
101  * Revision 1.23  2008/02/28 16:57:51  james
102  * *** empty log message ***
103  *
104  * Revision 1.22  2008/02/28 01:47:44  james
105  * *** empty log message ***
106  *
107  * Revision 1.21  2008/02/27 16:01:24  james
108  * *** empty log message ***
109  *
110  * Revision 1.20  2008/02/27 10:00:34  james
111  * *** empty log message ***
112  *
113  * Revision 1.19  2008/02/27 09:47:05  james
114  * *** empty log message ***
115  *
116  * Revision 1.18  2008/02/27 09:42:53  james
117  * *** empty log message ***
118  *
119  * Revision 1.17  2008/02/27 09:42:21  james
120  * *** empty log message ***
121  *
122  * Revision 1.16  2008/02/27 01:31:38  james
123  * *** empty log message ***
124  *
125  * Revision 1.15  2008/02/27 01:31:14  james
126  * *** empty log message ***
127  *
128  * Revision 1.14  2008/02/24 00:43:55  james
129  * *** empty log message ***
130  *
131  * Revision 1.13  2008/02/24 00:42:53  james
132  * *** empty log message ***
133  *
134  * Revision 1.12  2008/02/23 11:48:52  james
135  * *** empty log message ***
136  *
137  * Revision 1.11  2008/02/20 20:16:07  james
138  * *** empty log message ***
139  *
140  * Revision 1.10  2008/02/20 19:44:37  james
141  * @@
142  *
143  * Revision 1.9  2008/02/20 18:49:11  staffcvs
144  * *** empty log message ***
145  *
146  * Revision 1.8  2008/02/20 18:33:37  james
147  * *** empty log message ***
148  *
149  * Revision 1.7  2008/02/20 18:31:44  james
150  * *** empty log message ***
151  *
152  * Revision 1.6  2008/02/20 17:18:33  james
153  * *** empty log message ***
154  *
155  * Revision 1.5  2008/02/20 15:50:14  james
156  * *** empty log message ***
157  *
158  * Revision 1.4  2008/02/20 02:11:35  james
159  * *** empty log message ***
160  *
161  * Revision 1.3  2008/02/14 02:46:44  james
162  * *** empty log message ***
163  *
164  * Revision 1.2  2008/02/14 00:57:58  james
165  * *** empty log message ***
166  *
167  * Revision 1.1  2008/02/05 14:25:49  james
168  * *** empty log message ***
169  *
170  */
171
172 #include <sys/types.h>
173 #include <stdarg.h>
174 #include <sympathy.h>
175 #include <stdlib.h>
176 #include <sys/utsname.h>
177 #include <sys/stat.h>
178 #include <dirent.h>
179 #include <string.h>
180 #include <strings.h>
181 #include <malloc.h>
182 #include <fcntl.h>
183 #include <sys/resource.h>
184 #include <sys/wait.h>
185 #include <syslog.h>
186
187
188 #include "mainloop.h"
189
190 int use_syslog = 0;
191
192 extern void usage (void);
193 extern char *expand (const char *, int *);
194 static char hostname[1024];
195
196 char *socket_dirs[] =
197   { "~/.sympathy", "~/sympathy", "/etc/sympathy", "/var/sympathy", NULL };
198
199 int
200 safe_atoi (char *a)
201 {
202   char *end;
203   int ret;
204
205   if (!a)
206     return -1;
207
208   ret = (int) strtol (a, &end, 0);
209
210   if (end == a)
211     return -1;
212
213   return ret;
214 }
215
216 char *
217 fatal_moan (char *fmt, ...)
218 {
219   va_list ap;
220
221
222   va_start (ap, fmt);
223
224   if (use_syslog)
225     {
226       vsyslog (LOG_ERR, fmt, ap);
227     }
228   else
229     {
230       vfprintf (stderr, fmt, ap);
231       putc ('\n', stderr);
232     }
233   va_end (ap);
234
235   exit (1);
236 }
237
238 static void
239 sigchld (int dummy)
240 {
241   int status;
242   wait3 (&status, WNOHANG, NULL);
243 }
244
245 /* Dispell zombies, from, for example, log compression */
246 void
247 garlic (void)
248 {
249   struct sigaction sa;
250
251   sa.sa_handler = sigchld;
252   sa.sa_flags = SA_RESTART;
253   sigaction (SIGCHLD, &sa, NULL);
254 }
255
256 char *
257 teedious_snprintf (char *fmt, va_list ap)
258 {
259   va_list aq;
260   int size = 1024;
261   char *buf = malloc (size);
262   int n;
263
264   if (!buf)
265     fatal_moan ("malloc failed");
266
267   while (1)
268     {
269
270       va_copy (aq, ap);
271       n = vsnprintf (buf, size, fmt, aq);
272       va_end (aq);
273
274       if (n > -1 && n < (size))
275         return buf;
276
277       if (n > -1)               /* glibc 2.1 */
278         size = n + 1;
279       else                      /* glibc 2.0 */
280         size *= 2;              /* twice the old size */
281
282       buf = realloc (buf, size);
283
284       if (!buf)
285         fatal_moan ("malloc failed");
286     }
287
288 }
289
290 char *
291 gloo_paths (char *dir, char *leaf)
292 {
293   int i;
294   char *ret, *ptr;
295   if (!dir)
296     dir = "";
297   if (!leaf)
298     leaf = "";
299   ret = ptr = xmalloc (strlen (dir) + strlen (leaf) + 2);
300
301   while (*dir)
302     *(ptr++) = *(dir++);
303   *(ptr++) = '/';
304   while (*leaf)
305     *(ptr++) = *(leaf++);
306   *ptr = 0;
307
308   return ret;
309 }
310
311
312 /* make the path in fmt from home (hence the name) */
313 char *
314 mome (char *fmt, ...)
315 {
316   char *ret, *home, *leaf;
317   va_list ap;
318
319
320   home = getenv ("HOME");
321   if (!home)
322     return NULL;
323
324   if (fmt)
325     {
326       va_start (ap, fmt);
327       leaf = teedious_snprintf (fmt, ap);
328       va_end (ap);
329     }
330   else
331     {
332       leaf = NULL;
333     }
334
335   ret = gloo_paths (home, leaf);
336   if (leaf)
337     free (leaf);
338
339   return ret;
340 }
341
342
343
344 Socket *
345 find_socket (char **retpath, char *fmt, ...)
346 {
347   Socket *ret;
348   char *path, *leaf, *h, **ptr;
349   va_list ap;
350
351
352   if (fmt)
353     {
354       va_start (ap, fmt);
355       leaf = teedious_snprintf (fmt, ap);
356       va_end (ap);
357     }
358   else
359     {
360       leaf = NULL;
361     }
362
363
364   for (ptr = socket_dirs; *ptr; ptr++)
365     {
366       if (**ptr == '~')
367         {
368           h = mome (*ptr + 1);
369         }
370       else
371         {
372           h = *ptr;
373         }
374
375       if (!h)
376         continue;
377
378
379       path = gloo_paths (h, leaf);
380       if (**ptr == '~')
381         free (h);
382
383       ret = socket_connect (path);
384
385
386       if (ret)
387         {
388           if (retpath)
389             {
390               *retpath = path;
391             }
392           else
393             {
394               free (path);
395             }
396           free (leaf);
397           return ret;
398         }
399       free (path);
400
401     }
402
403   free (leaf);
404   return NULL;
405
406 }
407
408
409
410 int
411 list_sockets_in_dir (char *sockdir)
412 {
413   struct dirent *ent;
414   struct stat buf;
415   char *sn = NULL;
416   Socket *s;
417   DIR *dir = opendir (sockdir);
418
419
420
421   int hostname_len = strlen (hostname);
422
423   if (!dir)
424     return;
425
426   rewinddir (dir);
427
428
429   while ((ent = readdir (dir)))
430     {
431       sn = gloo_paths (sockdir, ent->d_name);
432       if (stat (sn, &buf) || (!S_ISSOCK (buf.st_mode)))
433         {
434           free (sn);
435           continue;
436         }
437
438       s = socket_connect (sn);
439
440       if (s)
441         {
442           printf ("\t%s         (Active)\n", sn);
443           socket_free (s);
444         }
445       else
446         {
447           if (strncmp (ent->d_name, hostname, hostname_len))
448             {
449               printf ("\t%s     (Unknown - not this host)\n", sn);
450             }
451           else
452             {
453               printf ("\t%s     (Dead, wiped)\n", sn);
454               unlink (sn);
455             }
456         }
457
458       free (sn);
459     }
460
461   closedir (dir);
462
463   return 0;
464 }
465
466 int
467 list_sockets (void)
468 {
469   char **ptr, *h;
470
471
472   for (ptr = socket_dirs; *ptr; ptr++)
473     {
474       if (**ptr == '~')
475         {
476           h = mome (*ptr + 1);
477         }
478       else
479         {
480           h = *ptr;
481         }
482
483       if (!h)
484         continue;
485
486       list_sockets_in_dir (h);
487
488       if (**ptr == '~')
489         free (h);
490
491     }
492
493   return 0;
494 }
495
496 void
497 get_hostname (void)
498 {
499   struct utsname name;
500
501   if (uname (&name))
502     {
503       strcpy (hostname, "unknown.");
504       return;
505     }
506
507
508   strcpy (hostname, name.nodename);
509   strcat (hostname, ".");
510 }
511
512 void
513 send_to_server (Socket * c, char *s)
514 {
515   int n;
516
517   s = expand (s, &n);
518
519   if (!n)
520     return;
521
522   while (n--)
523     {
524       ipc_msg_send_key (c, *(uint8_t *) s);
525       s++;
526     }
527   ipc_msg_send_killme (c);
528 }
529
530 int
531 main (int argc, char *argv[])
532 {
533   Context ctx_store = { 0 }, *ctx = &ctx_store;
534   int c;
535   extern char *optarg;
536   extern int optind, opterr, optopt;
537   CRT_Pos size = { VT102_COLS_80, VT102_ROWS_24 };
538
539   ANSI *ansi = NULL;
540
541   int cs_pipe[2] = { 0 };
542   int cs = 0;
543
544   int oflags[128];
545   char *oargs[128];
546
547   Socket *server_socket = NULL, *client_socket = NULL;
548
549   int history = 200;
550   int pid;
551
552   char *pid_file = NULL;
553
554   get_hostname ();
555
556   memset (oflags, 0, sizeof (oflags));
557   memset (oargs, 0, sizeof (oargs));
558
559   while ((c = getopt (argc, argv, "BI:NCSRP:vw:utscr:lKHd:pb:fL:Fk:n:")) != EOF)
560     {
561       switch (c)
562         {
563         case ':':
564         case 'h':
565         case '?':
566           usage ();
567         case 'S':
568           use_syslog++;
569           openlog ("sympathy", LOG_PID | LOG_CONS, LOG_DAEMON);
570           /*fall through */
571         default:
572           if ((c >= 'A') && (c <= 'Z'))
573             {
574               oflags[c]++;
575               oargs[c] = optarg;
576             }
577           else if ((c >= 'a') && (c <= 'z'))
578             {
579               oflags[c]++;
580               oargs[c] = optarg;
581             }
582           else
583             {
584               if (use_syslog)
585                 {
586                   syslog (LOG_ERR, "unknown option %c\n", c);
587                 }
588               else
589                 {
590                   fprintf (stderr, "unknown option %c\n", c);
591                 }
592               usage ();
593             }
594         }
595
596     }
597
598
599   /* Compatability for screen's ls */
600   if (oflags['l'])
601     oflags['s'] = 0;
602
603
604   {
605     int sum = 0;
606     sum += oflags['t'];
607     sum += (oflags['s'] || oflags['c']) ? 1 : 0;
608     sum += oflags['r'];
609     sum += oflags['l'];
610     sum += oflags['v'];
611     sum += oflags['C'];
612
613     if (!sum)
614       {
615         /* If no mode is specified behave like screen */
616         oflags['s']++;
617         oflags['c']++;
618         sum++;
619       }
620
621     if (sum != 1)
622       fatal_moan
623         ("specifiy exactly one of ( -c and or -s ), -t, -r, -C, -l and -v");
624   }
625
626   if (oflags['v'])
627     {
628       fprintf (stderr, "Version: %s\n", libsympathy_version ());
629       fprintf (stderr, "Version: %s\n", rcsid);
630       return 0;
631     }
632
633   if (oflags['l'])
634     return list_sockets ();
635
636
637   if (oflags['r'] && oflags['k'])
638     fatal_moan ("-k is incompatible with -r");
639
640
641   if (oflags['n'])
642     {
643       history = safe_atoi (oargs['n']);
644       if (history < 0)
645         fatal_moan ("cannot parse -n %s as an integer", oargs['n']);
646
647       if (!history)
648         fatal_moan ("agrument to -n must be greater than zero");
649     }
650
651   /* Fold -r implies -c */
652   if (oflags['r'])
653     oflags['c']++;
654
655   if (oflags['p'] && oflags['d'])
656     fatal_moan ("-p incompatible with -d");
657
658
659   if (oflags['c'] && oflags['s'] && oflags['F'])
660     fatal_moan ("-F is incompatible with -c -s");
661
662   if (oflags['H'] && oflags['N'])
663     fatal_moan ("-H is incompatible with -N");
664
665   /* implement server and client: this process forks. The parent */
666   /* becomes the client and the child forks again to become the */
667   /* server. If there's no -k argument the client (parent) needs */
668   /* to find out the pid of the server, we use a pipe */
669
670   if (oflags['s'] && oflags['c'])
671     {
672       cs++;
673       int result;
674       result = pipe (cs_pipe);
675
676       switch (pid = fork ())
677         {
678         case 0:                /* child becomes the server */
679           oflags['c'] = 0;
680           oflags['H'] = 0;
681           oflags['N'] = 0;
682           oflags['I'] = 0;
683
684           close (cs_pipe[0]);
685           break;
686         case -1:
687           fatal_moan ("fork failed");
688         default:               /* parent becomes client */
689           oflags['s'] = 0;
690           oflags['K'] = 0;
691           oflags['d'] = 0;
692           oflags['p'] = 0;
693           oflags['b'] = 0;
694           oflags['f'] = 0;
695           oflags['L'] = 0;
696           oflags['R'] = 0;
697           oflags['B'] = 0;
698           oflags['P'] = 0;
699           oflags['n'] = 0;
700           oflags['w'] = 0;
701
702           /* Collect the child */
703           waitpid (pid, NULL, 0);
704
705           /* if there was no k argument we need to find the */
706           /* pid of the server process so that we can work out */
707           /* what the socket is called. The server tells us on */
708           /* a pipe. We do this even if k is specified to avoid */
709           /* a race, the server writes to the pipe when the socket */
710           /* is opened */
711
712           close (cs_pipe[1]);
713
714           if (read (cs_pipe[0], &pid, sizeof (pid)) != sizeof (pid))
715             fatal_moan ("Failed to receive pid of server process");
716
717           close (cs_pipe[0]);
718
719           if (!oflags['k'])
720             {
721               oargs['k'] = mome ("/.sympathy/%s%d", hostname, pid);
722               oflags['k']++;
723             }
724         }
725     }
726
727
728
729   if (oflags['c'] && !oflags['k'] && !oflags['r'])
730     fatal_moan ("-c requires a socket to be specified with -s or -k or -r");
731
732   if ((oflags['H'] || oflags['N'] || oflags['I']) && oflags['s'])
733     fatal_moan ("-s is incompatible with -H, -N and -I");
734
735   if ((oflags['p'] || oflags['d'] || oflags['K'] || oflags['b'] || oflags['f']
736        || oflags['L'] || oflags['R'] || oflags['B'] || oflags['P']) && oflags['c'])
737     fatal_moan
738       ("-c or -r are incompatible with -p, -d, -K, -b, -f, -R, -P, -B or -L");
739
740   if (oflags['C'] && (!oflags['d']))
741     fatal_moan ("-C requires -d");
742
743
744   if (oflags['t'] || oflags['s'])
745     {
746       if (!oflags['p'] && !oflags['d'])
747         oflags['p']++;
748     }
749
750   if (oflags['w'])
751     {
752       char buf[128], *ptr;
753       strcpy (buf, oargs['w']);
754       ptr = index (buf, 'x');
755       if (ptr)
756         {
757           *ptr = 0;
758           ptr++;
759           size.y = safe_atoi (ptr);
760         }
761       size.x = safe_atoi (buf);
762
763       if ((size.x > VT102_MAX_COLS) || (size.x < 1))
764         fatal_moan ("-w requires a width between 1 and %d\n", VT102_MAX_COLS);
765
766       if ((size.y > VT102_MAX_ROWS) || (size.y < 1))
767         fatal_moan ("-w requires a height between 1 and %d\n",
768                     VT102_MAX_ROWS);
769
770     }
771
772   if (oflags['s'] && !oflags['F'])
773     {
774       /* nochdir incase socket is relative path, unlink then will fail */
775       int fish;
776       fish = daemon (1, 0);
777
778     }
779
780   garlic ();
781
782   if (oflags['s'])
783     {
784       char *path;
785       path = mome ("/.sympathy");
786       mkdir (path, 0700);
787       free (path);
788
789
790       if (!oflags['k'])
791         {
792           pid = getpid ();
793
794           oargs['k'] = mome ("/.sympathy/%s%d", hostname, pid);
795           oflags['k']++;
796         }
797
798       server_socket = socket_listen (oargs['k']);
799
800       /* Tell our parent's parent what our pid is */
801       /* and that we've opened the server socket */
802       if (cs)
803         {
804           pid = getpid ();
805
806           int fish;
807           fish = write (cs_pipe[1], &pid, sizeof (pid));
808           close (cs_pipe[1]);
809         }
810
811       if (!server_socket)
812         fatal_moan ("failed to create socket %s for listening", oargs['k']);
813
814     }
815
816   if (oflags['s'] || oflags['t'] || oflags['C'])
817     {
818       if (oflags['P'])
819         {
820           FILE *fp;
821           pid_file = oargs['P'];
822           fp = fopen (pid_file, "w");
823           if (fp)
824             {
825               fprintf (fp, "%d", getpid ());
826               fclose (fp);
827             }
828         }
829
830       if (oflags['L'])
831         {
832           ctx->l = file_log_new (oargs['L'], oflags['R']);
833           ctx->byte_logging=oflags['B'];
834           if (!ctx->l)
835             fatal_moan ("unable to access log file %s", oargs['L']);
836         }
837
838       if (oflags['p'])
839         {
840           if (optind < argc)
841             {
842               ctx->t = ptty_open (argv[optind], &argv[optind], &size);
843             }
844           else
845             {
846               ctx->t = ptty_open (NULL, NULL, &size);
847             }
848
849           if (!ctx->t)
850             fatal_moan ("unable to open a ptty");
851         }
852       else
853         {
854           /* HACK-- check that console=device does not occur in */
855           /* /proc/cmdline */
856           if (!oargs['d'])
857             fatal_moan ("no argument to -d");
858
859           {
860             char kernel_cmdline[4096] = { 0 };
861             char search_string[1024] = "console=";
862             char *ptr = oargs['d'];
863             int fd;
864
865             if (!strncmp ("/dev/", ptr, 5))
866               ptr += 5;
867
868             strcat (search_string, ptr);
869
870             fd = open ("/proc/cmdline", O_RDONLY);
871             int fish;
872             fish = read (fd, kernel_cmdline, sizeof (kernel_cmdline));
873             close (fd);
874
875             kernel_cmdline[sizeof (kernel_cmdline) - 1] = 0;
876
877             if (strstr (kernel_cmdline, search_string))
878               fatal_moan ("/proc/cmdline contains %s", search_string);
879           }
880
881           ctx->t =
882             serial_open (oargs['d'],
883                          oflags['K'] ? SERIAL_LOCK_ACTIVE :
884                          SERIAL_LOCK_PASSIVE);
885           if (!ctx->t)
886             fatal_moan ("unable to open serial port %s", oargs['d']);
887
888           if (oflags['C'])
889             {
890               ctx->t->close (ctx->t);
891               return 0;
892             }
893         }
894
895       if (oflags['b'])
896         {
897           int baud = safe_atoi (oargs['b']);
898
899           if (baud < 0)
900             fatal_moan ("Unable to parse baudrate %s", oargs['b']);
901
902           tty_set_baud (ctx->t, baud);
903
904         }
905
906       tty_set_flow (ctx->t, oflags['f'] ? 1 : 0);
907     }
908
909
910   if (oflags['r'])
911     {
912       char *id = oargs['r'];
913
914       if (!id)
915         fatal_moan ("-r requires an argument");
916
917       if (safe_atoi (id) > 0)
918         {
919           client_socket =
920             find_socket (&oargs['k'], "%s%d", hostname, safe_atoi (id));
921         }
922       else
923         {
924           client_socket = find_socket (&oargs['k'], "%s", id);
925         }
926
927       if (!client_socket)
928         fatal_moan ("failed to find socket %s", oargs['r']);
929
930     }
931   else if (oflags['c'])
932     {
933       client_socket = socket_connect (oargs['k']);
934
935       if (!client_socket)
936         fatal_moan ("failed to connect to socket %s", oargs['k']);
937
938     }
939
940   if (oflags['I'])
941     {
942       if (!client_socket)
943         fatal_moan ("-I requires either -c or -r", oargs['k']);
944       if (!oargs['I'])
945         fatal_moan ("-I requires an arugment");
946       send_to_server (client_socket, oargs['I']);
947     }
948   else
949     {
950       if (client_socket)
951         ipc_msg_send_initialize (client_socket);
952
953       if (oflags['c'] || oflags['t'])
954         {
955           if (oflags['N'])
956             {
957               ctx->r = rx_new_raw (0, 1);
958               ansi = ansi_new_raw (0, 1);
959             }
960           else if (oflags['H'])
961             {
962               ansi = ansi_new_html (stdout);
963             }
964           else
965             {
966               terminal_register_handlers ();
967               ansi =
968                 ansi_new_from_terminal (terminal_open (0, 1),
969                                         oflags['u'] ? 0 : 1);
970               ansi->reset (ansi, NULL);
971
972             }
973
974           if (ansi->set_title)
975             {
976               if (oflags['c'] && oargs['k'])
977                 {
978                   ansi->set_title (ansi, oargs['k']);
979                 }
980               else if ((ctx->t) && (ctx->t->name))
981                 {
982                   ansi->set_title (ansi, ctx->t->name);
983                 }
984             }
985
986         }
987     }
988
989   ctx->v = vt102_new (&size);
990   ctx->h = history_new (history);
991
992   mainloop (ctx, ansi, server_socket, client_socket);
993
994   if (ansi)
995     {
996       ansi->close (ansi);
997       terminal_atexit ();
998     }
999
1000   if (ctx->t)
1001     ctx->t->close (ctx->t);
1002
1003   if (ctx->l)
1004     ctx->l->close (ctx->l);
1005   if (server_socket)
1006     socket_free (server_socket);
1007   if (client_socket)
1008     socket_free (client_socket);
1009
1010   if (pid_file)
1011     unlink (pid_file);
1012
1013   if (!oflags['H'] && !oflags['I'])
1014     printf ("you have now exited sympathy\n");
1015   return 0;
1016 }