source: owl.c @ 2fa15f0

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 2fa15f0 was 2fa15f0, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 17 years ago
1) Fix massive memory leak. I've removed the variable that held the mainloop hook name, replacing the two references to it with the hard-coded function "owl::mainloop_hook". We were discussing doing this anyhow, and since leak was in getting the variable over and over again, this was the easiest way to deal. 2) Updated owlconf.pl in light of (1). Update your local copy! 3) jabber - groupchat history is not requested, and is explicitly ignored.
  • Property mode set to 100644
File size: 25.6 KB
Line 
1/*  Copyright (c) 2004 James Kretchmar. All rights reserved.
2 *
3 *  Redistribution and use in source and binary forms, with or without
4 *  modification, are permitted provided that the following conditions are
5 *  met:
6 * 
7 *    * Redistributions of source code must retain the above copyright
8 *      notice, this list of conditions and the following disclaimer.
9 * 
10 *    * Redistributions in binary form must reproduce the above copyright
11 *      notice, this list of conditions and the following disclaimer in
12 *      the documentation and/or other materials provided with the
13 *      distribution.
14 * 
15 *    * Redistributions in any form must be accompanied by information on
16 *      how to obtain complete source code for the Owl software and any
17 *      accompanying software that uses the Owl software. The source code
18 *      must either be included in the distribution or be available for no
19 *      more than the cost of distribution plus a nominal fee, and must be
20 *      freely redistributable under reasonable conditions. For an
21 *      executable file, complete source code means the source code for
22 *      all modules it contains. It does not include source code for
23 *      modules or files that typically accompany the major components of
24 *      the operating system on which the executable file runs.
25 * 
26 *
27 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29 *  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
30 *  NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
31 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
34 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
36 *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
37 *  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#include <stdio.h>
41#include <unistd.h>
42#include <stdlib.h>
43#include <string.h>
44#include <signal.h>
45#include <time.h>
46#include <sys/param.h>
47#include <sys/types.h>
48#include <termios.h>
49#include <sys/stat.h>
50#include "owl.h"
51
52#if OWL_STDERR_REDIR
53#ifdef HAVE_SYS_IOCTL_H
54#include <sys/ioctl.h>
55#endif
56#ifdef HAVE_SYS_FILIO_H
57#include <sys/filio.h>
58#endif
59int stderr_replace(void);
60#endif
61
62static const char fileIdent[] = "$Id$";
63
64owl_global g;
65
66int main(int argc, char **argv, char **env)
67{
68  WINDOW *recwin, *sepwin, *typwin, *msgwin;
69  owl_editwin *tw;
70  owl_popwin *pw;
71  int j, ret, initialsubs, debug, argcsave, followlast;
72  int newmsgs, zpendcount, nexttimediff;
73  struct sigaction sigact;
74  char *configfile, *tty, *perlout, *perlerr, **argvsave, buff[LINE], startupmsg[LINE];
75  owl_filter *f;
76  owl_style *s;
77  time_t nexttime, now;
78  struct tm *today;
79  char *dir;
80  struct termios tio;
81#ifdef HAVE_LIBZEPHYR
82  ZNotice_t notice;
83#endif
84#if OWL_STDERR_REDIR
85  int newstderr;
86#endif
87
88  argcsave=argc;
89  argvsave=argv;
90  configfile=NULL;
91  tty=NULL;
92  debug=0;
93  initialsubs=1;
94  if (argc>0) {
95    argv++;
96    argc--;
97  }
98  while (argc>0) {
99    if (!strcmp(argv[0], "-n")) {
100      initialsubs=0;
101      argv++;
102      argc--;
103    } else if (!strcmp(argv[0], "-c")) {
104      if (argc<2) {
105        fprintf(stderr, "Too few arguments to -c\n");
106        usage();
107        exit(1);
108      }
109      configfile=argv[1];
110      argv+=2;
111      argc-=2;
112    } else if (!strcmp(argv[0], "-t")) {
113      if (argc<2) {
114        fprintf(stderr, "Too few arguments to -t\n");
115        usage();
116        exit(1);
117      }
118      tty=argv[1];
119      argv+=2;
120      argc-=2;
121    } else if (!strcmp(argv[0], "-d")) {
122      debug=1;
123      argv++;
124      argc--;
125    } else if (!strcmp(argv[0], "-D")) {
126      debug=1;
127      unlink(OWL_DEBUG_FILE);
128      argv++;
129      argc--;
130    } else if (!strcmp(argv[0], "-v")) {
131      printf("This is owl version %s\n", OWL_VERSION_STRING);
132      exit(0);
133    } else {
134      fprintf(stderr, "Uknown argument\n");
135      usage();       
136      exit(1);
137    }
138  }
139
140  owl_function_debugmsg("startup: Finished parsing arguments");
141
142#ifdef HAVE_LIBZEPHYR
143  /* zephyr init */
144  ret=owl_zephyr_initialize();
145  if (ret) {
146    exit(1);
147  }
148#endif
149 
150  /* signal handler */
151  /*sigact.sa_handler=sig_handler;*/
152  sigact.sa_sigaction=sig_handler;
153  sigemptyset(&sigact.sa_mask);
154  sigact.sa_flags=SA_SIGINFO;
155  sigaction(SIGWINCH, &sigact, NULL);
156  sigaction(SIGALRM, &sigact, NULL);
157  sigaction(SIGPIPE, &sigact, NULL);
158  sigaction(SIGTERM, &sigact, NULL);
159  sigaction(SIGHUP, &sigact, NULL);
160
161  /* save initial terminal settings */
162  tcgetattr(0, owl_global_get_startup_tio(&g));
163
164  /* turn ISTRIP off */
165  tcgetattr(0, &tio);
166  tio.c_iflag &= ~ISTRIP;
167  tcsetattr(0, TCSAFLUSH, &tio);
168
169  /* screen init */
170  if (!getenv("TERMINFO")) {
171    sprintf(buff, "TERMINFO=%s", TERMINFO);
172    putenv(buff);
173    owl_function_debugmsg("startup: setting TERMINFO to %s", TERMINFO);
174  } else {
175    owl_function_debugmsg("startup: leaving TERMINFO as %s from envrionment", getenv("TERMINFO"));
176  }
177  initscr();
178  start_color();
179#ifdef HAVE_USE_DEFAULT_COLORS
180  use_default_colors();
181#endif
182  raw();
183  noecho();
184
185  /* define simple color pairs */
186  if (has_colors() && COLOR_PAIRS>=8) {
187    init_pair(OWL_COLOR_BLACK,   COLOR_BLACK,   -1);
188    init_pair(OWL_COLOR_RED,     COLOR_RED,     -1);
189    init_pair(OWL_COLOR_GREEN,   COLOR_GREEN,   -1);
190    init_pair(OWL_COLOR_YELLOW,  COLOR_YELLOW,  -1);
191    init_pair(OWL_COLOR_BLUE,    COLOR_BLUE,    -1);
192    init_pair(OWL_COLOR_MAGENTA, COLOR_MAGENTA, -1);
193    init_pair(OWL_COLOR_CYAN,    COLOR_CYAN,    -1);
194    init_pair(OWL_COLOR_WHITE,   COLOR_WHITE,   -1);
195  }
196
197  /* owl global init */
198  owl_global_init(&g);
199  if (debug) owl_global_set_debug_on(&g);
200  owl_function_debugmsg("startup: first available debugging message");
201  owl_global_set_startupargs(&g, argcsave, argvsave);
202#ifdef HAVE_LIBZEPHYR
203  owl_global_set_havezephyr(&g);
204#endif
205  owl_global_set_haveaim(&g);
206
207#if OWL_STDERR_REDIR
208  /* Do this only after we've started curses up... */
209  owl_function_debugmsg("startup: doing stderr redirection");
210  newstderr = stderr_replace();
211  owl_muxevents_add(owl_global_get_muxevents(&g), newstderr, OWL_MUX_READ,
212                    stderr_redirect_handler, NULL);
213#endif   
214
215  /* create the owl directory, in case it does not exist */
216  owl_function_debugmsg("startup: creating owl directory, if not present");
217  dir=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_CONFIG_DIR);
218  mkdir(dir, S_IRWXU);
219  owl_free(dir);
220
221  /* set the tty, either from the command line, or by figuring it out */
222  owl_function_debugmsg("startup: setting tty name");
223  if (tty) {
224    owl_global_set_tty(&g, tty);
225  } else {
226    owl_global_set_tty(&g, owl_util_get_default_tty());
227  }
228
229  /* setup the built-in styles */
230  owl_function_debugmsg("startup: creating built-in styles");
231  s=owl_malloc(sizeof(owl_style));
232  owl_style_create_internal(s, "default", &owl_stylefunc_default, "Default message formatting");
233  owl_global_add_style(&g, s);
234
235  s=owl_malloc(sizeof(owl_style));
236  owl_style_create_internal(s, "basic", &owl_stylefunc_basic, "Basic message formatting.");
237  owl_global_add_style(&g, s);
238#if 0
239  s=owl_malloc(sizeof(owl_style));
240  owl_style_create_internal(s, "vt", &owl_stylefunc_vt, "VT message formatting.");
241  owl_global_add_style(&g, s);
242#endif
243  s=owl_malloc(sizeof(owl_style));
244  owl_style_create_internal(s, "oneline", &owl_stylefunc_oneline, "Formats for one-line-per-message");
245  owl_global_add_style(&g, s);
246
247  /* setup the default filters */
248  /* the personal filter will need to change again when AIM chat's are
249   *  included.  Also, there should be an %aimme% */
250  owl_function_debugmsg("startup: creating default filters");
251  f=owl_malloc(sizeof(owl_filter));
252  owl_filter_init_fromstring(f, "personal", "( type ^zephyr$ "
253                             "and class ^message$ and instance ^personal$ "
254                             "and ( recipient ^%me%$ or sender ^%me%$ ) ) "
255                             "or ( type ^aim$ and login ^none$ )");
256  owl_list_append_element(owl_global_get_filterlist(&g), f);
257
258  f=owl_malloc(sizeof(owl_filter));
259  owl_filter_init_fromstring(f, "trash", "class ^mail$ or opcode ^ping$ or type ^admin$ or ( not login ^none$ )");
260  owl_list_append_element(owl_global_get_filterlist(&g), f);
261
262  f=owl_malloc(sizeof(owl_filter));
263  owl_filter_init_fromstring(f, "ping", "opcode ^ping$");
264  owl_list_append_element(owl_global_get_filterlist(&g), f);
265
266  f=owl_malloc(sizeof(owl_filter));
267  owl_filter_init_fromstring(f, "auto", "opcode ^auto$");
268  owl_list_append_element(owl_global_get_filterlist(&g), f);
269
270  f=owl_malloc(sizeof(owl_filter));
271  owl_filter_init_fromstring(f, "login", "not login ^none$");
272  owl_list_append_element(owl_global_get_filterlist(&g), f);
273
274  f=owl_malloc(sizeof(owl_filter));
275  owl_filter_init_fromstring(f, "reply-lockout", "class ^noc or class ^mail$");
276  owl_list_append_element(owl_global_get_filterlist(&g), f);
277
278  f=owl_malloc(sizeof(owl_filter));
279  owl_filter_init_fromstring(f, "out", "direction ^out$");
280  owl_list_append_element(owl_global_get_filterlist(&g), f);
281
282  f=owl_malloc(sizeof(owl_filter));
283  owl_filter_init_fromstring(f, "aim", "type ^aim$");
284  owl_list_append_element(owl_global_get_filterlist(&g), f);
285
286  f=owl_malloc(sizeof(owl_filter));
287  owl_filter_init_fromstring(f, "zephyr", "type ^zephyr$");
288  owl_list_append_element(owl_global_get_filterlist(&g), f);
289
290  f=owl_malloc(sizeof(owl_filter));
291  owl_filter_init_fromstring(f, "none", "false");
292  owl_list_append_element(owl_global_get_filterlist(&g), f);
293
294  f=owl_malloc(sizeof(owl_filter));
295  owl_filter_init_fromstring(f, "all", "true");
296  owl_list_append_element(owl_global_get_filterlist(&g), f);
297
298  /* set the current view */
299  owl_function_debugmsg("startup: setting the current view");
300  owl_view_create(owl_global_get_current_view(&g), "main", f, owl_global_get_style_by_name(&g, "default"));
301
302  /* AIM init */
303  owl_function_debugmsg("startup: doing AIM initialization");
304  owl_aim_init();
305
306  /* process the startup file */
307  owl_function_debugmsg("startup: processing startup file");
308  owl_function_source(NULL);
309
310  /* read the config file */
311  owl_function_debugmsg("startup: processing config file");
312  owl_context_set_readconfig(owl_global_get_context(&g));
313  perlerr=owl_perlconfig_readconfig(configfile);
314  if (perlerr) {
315    endwin();
316    owl_function_error("Error parsing configfile: %s\n", perlerr);
317    fprintf(stderr, "\nError parsing configfile: %s\n", perlerr);
318    fflush(stderr);
319    printf("\nError parsing configfile: %s\n", perlerr);
320    fflush(stdout);
321    exit(1);
322  }
323
324  /* if the config defines a formatting function, add 'perl' as a style */
325  if (owl_global_is_config_format(&g)) {
326    owl_function_debugmsg("Found perl formatting");
327    s=owl_malloc(sizeof(owl_style));
328    owl_style_create_perl(s, "perl", "owl::_format_msg_legacy_wrap",
329                          "User-defined perl style that calls owl::format_msg"
330                          "with legacy global variable support");
331    owl_global_add_style(&g, s);
332    owl_global_set_default_style(&g, "perl");
333  }
334
335  /* execute the startup function in the configfile */
336  owl_function_debugmsg("startup: executing perl startup, if applicable");
337  perlout = owl_perlconfig_execute("owl::startup();");
338  if (perlout) owl_free(perlout);
339 
340  /* hold on to the window names for convenience */
341  msgwin=owl_global_get_curs_msgwin(&g);
342  recwin=owl_global_get_curs_recwin(&g);
343  sepwin=owl_global_get_curs_sepwin(&g);
344  typwin=owl_global_get_curs_typwin(&g);
345  tw=owl_global_get_typwin(&g);
346
347  /* welcome message */
348  owl_function_debugmsg("startup: creating splash message");
349  strcpy(startupmsg, "-----------------------------------------------------------------------\n");
350  sprintf(buff,      "Welcome to Owl version %s.  Press 'h' for on-line help. \n", OWL_VERSION_STRING);
351  strcat(startupmsg, buff);
352  strcat(startupmsg, "                                                                       \n");
353  strcat(startupmsg, "This is an UNOFFICIAL DEVELOPMENT BUILD of owl. If you are using this  \n");
354  strcat(startupmsg, "build regularly, please add yourself to dirty-owl-hackers@mit.edu      \n");
355  strcat(startupmsg, "                                                                 ^ ^   \n");
356  strcat(startupmsg, "Any bugs should be reported to dirty-owl-hackers@mit.edu         OvO   \n");
357  strcat(startupmsg, "Do not seek help with this build from bug-owl or ktools.        (   )  \n");
358  strcat(startupmsg, "-----------------------------------------------------------------m-m---\n");
359  owl_function_adminmsg("", startupmsg);
360  sepbar(NULL);
361
362  wrefresh(sepwin);
363
364  /* load zephyr subs */
365  if (initialsubs) {
366    int ret2;
367    owl_function_debugmsg("startup: loading initial zephyr subs");
368
369    /* load default subscriptions */
370    ret=owl_zephyr_loaddefaultsubs();
371   
372    /* load subscriptions from subs file */
373    ret2=owl_zephyr_loadsubs(NULL, 0);
374
375    if (ret || ret2) {
376      owl_function_adminmsg("", "Error loading zephyr subscriptions");
377    } else if (ret2!=-1) {
378      owl_global_add_userclue(&g, OWL_USERCLUE_CLASSES);
379    }
380
381    /* load login subscriptions */
382    if (owl_global_is_loginsubs(&g)) {
383      owl_function_debugmsg("startup: loading login subs");
384      owl_function_loadloginsubs(NULL);
385    }
386  }
387
388  /* First buddy check to sync the list without notifications */
389  owl_function_debugmsg("startup: doing initial zephyr buddy check");
390  /* owl_function_zephyr_buddy_check(0); */
391
392  /* set the startup and default style, based on userclue and presence of a
393   * formatting function */
394  owl_function_debugmsg("startup: setting startup and default style");
395  if (0 != strcmp(owl_global_get_default_style(&g), "__unspecified__")) {
396    /* the style was set by the user: leave it alone */
397  } else if (owl_global_is_config_format(&g)) {
398    owl_global_set_default_style(&g, "perl");
399  } else if (owl_global_is_userclue(&g, OWL_USERCLUE_CLASSES)) {
400    owl_global_set_default_style(&g, "default");
401  } else {
402    owl_global_set_default_style(&g, "basic");
403  }
404
405  /* zlog in if we need to */
406  if (owl_global_is_startuplogin(&g)) {
407    owl_function_debugmsg("startup: doing zlog in");
408    owl_zephyr_zlog_in();
409  }
410
411  owl_function_debugmsg("startup: set style for the view");
412  owl_view_set_style(owl_global_get_current_view(&g), 
413                     owl_global_get_style_by_name(&g, owl_global_get_default_style(&g)));   
414
415  owl_function_debugmsg("startup: setting context interactive");
416  owl_context_set_interactive(owl_global_get_context(&g));
417
418  nexttimediff=10;
419  nexttime=time(NULL);
420
421  owl_function_debugmsg("startup: entering main loop");
422  /* main loop */
423  while (1) {
424
425    /* if a resize has been scheduled, deal with it */
426    owl_global_resize(&g, 0, 0);
427
428    /* these are here in case a resize changes the windows */
429    msgwin=owl_global_get_curs_msgwin(&g);
430    recwin=owl_global_get_curs_recwin(&g);
431    sepwin=owl_global_get_curs_sepwin(&g);
432    typwin=owl_global_get_curs_typwin(&g);
433
434    followlast=owl_global_should_followlast(&g);
435   
436    /* Do AIM stuff */
437    if (owl_global_is_doaimevents(&g)) {
438      owl_aim_process_events();
439
440      if (owl_global_is_aimloggedin(&g)) {
441        if (owl_timer_is_expired(owl_global_get_aim_buddyinfo_timer(&g))) {
442          /* owl_buddylist_request_idletimes(owl_global_get_buddylist(&g)); */
443          owl_timer_reset(owl_global_get_aim_buddyinfo_timer(&g));
444        }
445      }
446    }
447
448    /* Hook perl into the loop */
449
450    if (owl_perlconfig_is_function("owl::mainloop_hook")) {
451         perlout = owl_perlconfig_execute("owl::mainloop_hook");
452         if (perlout) owl_free(perlout);
453    }
454
455    /* little hack */
456    now=time(NULL);
457    today=localtime(&now);
458    if (today->tm_mon==9 && today->tm_mday==31 && owl_global_get_runtime(&g)<600) {
459      if (time(NULL)>nexttime) {
460        if (nexttimediff==1) {
461          nexttimediff=10;
462        } else {
463          nexttimediff=1;
464        }
465        nexttime+=nexttimediff;
466        owl_hack_animate();
467      }
468    }
469
470    /* Grab incoming messages. */
471    newmsgs=0;
472    zpendcount=0;
473    while(owl_zephyr_zpending() || owl_global_messagequeue_pending(&g)) {
474#ifdef HAVE_LIBZEPHYR
475      struct sockaddr_in from;
476#endif
477      owl_message *m=NULL;
478      owl_filter *f;
479
480      /* grab the new message, stick it in 'm' */
481      if (owl_zephyr_zpending()) {
482#ifdef HAVE_LIBZEPHYR
483        /* grab a zephyr notice, but if we've done 20 without stopping,
484           take a break to process keystrokes etc. */
485        if (zpendcount>20) break;
486        ZReceiveNotice(&notice, &from);
487        zpendcount++;
488       
489        /* is this an ack from a zephyr we sent? */
490        if (owl_zephyr_notice_is_ack(&notice)) {
491          owl_zephyr_handle_ack(&notice);
492          continue;
493        }
494       
495        /* if it's a ping and we're not viewing pings then skip it */
496        if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
497          continue;
498        }
499
500        /* create the new message */
501        m=owl_malloc(sizeof(owl_message));
502        owl_message_create_from_znotice(m, &notice);
503#endif
504      } else if (owl_global_messagequeue_pending(&g)) {
505        /* pick up the non-zephyr message in the message queue */
506        m=owl_global_messageuque_popmsg(&g);
507      } else {
508        /* Not supposed to happen, but we seem to get here on resizes */
509        owl_function_debugmsg("Bottomed out looking for zephyr");
510      }
511
512      /* If we didn't pick up a message for some reason, don't go on */
513      if (m==NULL) {
514        owl_function_debugmsg("m is null in main loop");
515        continue;
516      }
517     
518      /* if this message it on the puntlist, nuke it and continue */
519      if (owl_global_message_is_puntable(&g, m)) {
520        owl_message_free(m);
521        continue;
522      }
523
524      /*  login or logout that should be ignored? */
525      if (owl_global_is_ignorelogins(&g) && owl_message_is_loginout(m)) {
526        owl_message_free(m);
527        continue;
528      }
529
530      /* otherwise add it to the global list */
531      owl_messagelist_append_element(owl_global_get_msglist(&g), m);
532      newmsgs=1;
533
534      /* let the config know the new message has been received */
535      owl_perlconfig_getmsg(m, 0, NULL);
536
537      /* add it to any necessary views; right now there's only the current view */
538      owl_view_consider_message(owl_global_get_current_view(&g), m);
539
540      /* do we need to autoreply? */
541      if (owl_global_is_zaway(&g) && !owl_message_get_attribute_value(m, "isauto")) {
542        if (owl_message_is_type_zephyr(m)) {
543          owl_zephyr_zaway(m);
544        } else if (owl_message_is_type_aim(m)) {
545          if (owl_message_is_private(m)) {
546            owl_function_send_aimawymsg(owl_message_get_sender(m), owl_global_get_zaway_msg(&g));
547          }
548        }
549      }
550
551      /* ring the bell if it's a personal */
552      if (!strcmp(owl_global_get_personalbell(&g), "on")) {
553          if (!owl_message_is_loginout(m) &&
554              !owl_message_is_mail(m) &&
555              owl_message_is_private(m)) {
556            owl_function_beep();
557          }
558      } else if (!strcmp(owl_global_get_personalbell(&g), "off")) {
559        /* do nothing */
560      } else {
561        f=owl_global_get_filter(&g, owl_global_get_personalbell(&g));
562        if (f && owl_filter_message_match(f, m)) {
563          owl_function_beep();
564        }
565      }
566
567
568      /* if it matches the alert filter, do the alert action */
569      f=owl_global_get_filter(&g, owl_global_get_alert_filter(&g));
570      if (f && owl_filter_message_match(f, m)) {
571        owl_function_command(owl_global_get_alert_action(&g));
572      }
573
574      /* if it's a zephyr login or logout, update the zbuddylist */
575      if (owl_message_is_type_zephyr(m) && owl_message_is_loginout(m)) {
576        if (owl_message_is_login(m)) {
577          owl_zbuddylist_adduser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
578        } else if (owl_message_is_logout(m)) {
579          owl_zbuddylist_deluser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
580        } else {
581          owl_function_error("Internal error: received login notice that is neither login nor logout");
582        }
583      }
584
585      /* check for burning ears message */
586      /* this is an unsupported feature */
587      if (owl_global_is_burningears(&g) && owl_message_is_burningears(m)) {
588        char *buff;
589        buff = owl_sprintf("@i(Burning ears message on class %s)", owl_message_get_class(m));
590        owl_function_adminmsg(buff, "");
591        owl_free(buff);
592        owl_function_beep();
593      }
594
595      /* log the message if we need to */
596      owl_log_message(m);
597    }
598
599    /* is it time to check zbuddies? */
600    if (owl_global_is_pseudologins(&g)) {
601      if (owl_timer_is_expired(owl_global_get_zephyr_buddycheck_timer(&g))) {
602        owl_function_debugmsg("Doing zephyr buddy check");
603        owl_function_zephyr_buddy_check(1);
604        owl_timer_reset(owl_global_get_zephyr_buddycheck_timer(&g));
605      }
606    }
607
608    /* dispatch any muxevents */
609    owl_muxevents_dispatch(owl_global_get_muxevents(&g), 0);
610
611    /* follow the last message if we're supposed to */
612    if (newmsgs && followlast) {
613      owl_function_lastmsg_noredisplay();
614    }
615
616    /* do the newmsgproc thing */
617    if (newmsgs) {
618      owl_function_do_newmsgproc();
619    }
620   
621    /* redisplay if necessary */
622    /* this should be optimized to not run if the new messages won't be displayed */
623    if (newmsgs) {
624      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
625      sepbar(NULL);
626      if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
627        owl_popwin_refresh(owl_global_get_popwin(&g));
628        /* TODO: this is a broken kludge */
629        if (owl_global_get_viewwin(&g)) {
630          owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
631        }
632      }
633      owl_global_set_needrefresh(&g);
634    }
635
636    /* if a popwin just came up, refresh it */
637    pw=owl_global_get_popwin(&g);
638    if (owl_popwin_is_active(pw) && owl_popwin_needs_first_refresh(pw)) {
639      owl_popwin_refresh(pw);
640      owl_popwin_no_needs_first_refresh(pw);
641      owl_global_set_needrefresh(&g);
642      /* TODO: this is a broken kludge */
643      if (owl_global_get_viewwin(&g)) {
644        owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
645      }
646    }
647
648    /* update the terminal if we need to */
649    if (owl_global_is_needrefresh(&g)) {
650      /* leave the cursor in the appropriate window */
651      if (owl_global_is_typwin_active(&g)) {
652        owl_function_set_cursor(typwin);
653      } else {
654        owl_function_set_cursor(sepwin);
655      }
656      doupdate();
657      owl_global_set_noneedrefresh(&g);
658    }
659
660    /* Handle all keypresses.  If no key has been pressed, sleep for a
661     * little bit, but otherwise do not.  This lets input be grabbed
662     * as quickly as possbile */
663    j=wgetch(typwin);
664    if (j==ERR) {
665      usleep(10);
666    } else {
667      /* find and activate the current keymap.
668       * TODO: this should really get fixed by activating
669       * keymaps as we switch between windows...
670       */
671      if (pw && owl_popwin_is_active(pw) && owl_global_get_viewwin(&g)) {
672        owl_context_set_popless(owl_global_get_context(&g), 
673                                owl_global_get_viewwin(&g));
674        owl_function_activate_keymap("popless");
675      } else if (owl_global_is_typwin_active(&g) 
676                 && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_ONELINE) {
677        /*
678          owl_context_set_editline(owl_global_get_context(&g), tw);
679          owl_function_activate_keymap("editline");
680        */
681      } else if (owl_global_is_typwin_active(&g) 
682                 && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_MULTILINE) {
683        owl_context_set_editmulti(owl_global_get_context(&g), tw);
684        owl_function_activate_keymap("editmulti");
685      } else {
686        owl_context_set_recv(owl_global_get_context(&g));
687        owl_function_activate_keymap("recv");
688      }
689      /* now actually handle the keypress */
690      ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j);
691      if (ret!=0 && ret!=1) {
692        owl_function_makemsg("Unable to handle keypress");
693      }
694    }
695
696    /* Log any error signals */
697    {
698      siginfo_t si;
699      int signum;
700      if ((signum = owl_global_get_errsignal_and_clear(&g, &si)) > 0) {
701        owl_function_error("Got unexpected signal: %d %s  (code: %d band: %d  errno: %d)", 
702                           signum, signum==SIGPIPE?"SIGPIPE":"SIG????",
703                           si.si_code, si.si_band, si.si_errno);
704      }
705    }
706
707  }
708}
709
710void sig_handler(int sig, siginfo_t *si, void *data)
711{
712  if (sig==SIGWINCH) {
713    /* we can't inturrupt a malloc here, so it just sets a flag
714     * schedulding a resize for later
715     */
716    owl_function_resize();
717  } else if (sig==SIGPIPE || sig==SIGCHLD) {
718    /* Set a flag and some info that we got the sigpipe
719     * so we can record that we got it and why... */
720    owl_global_set_errsignal(&g, sig, si);
721  } else if (sig==SIGTERM || sig==SIGHUP) {
722    owl_function_quit();
723  }
724
725}
726
727void usage()
728{
729  fprintf(stderr, "Owl version %s\n", OWL_VERSION_STRING);
730  fprintf(stderr, "Usage: owl [-n] [-d] [-D] [-v] [-h] [-c <configfile>] [-t <ttyname>]\n");
731  fprintf(stderr, "  -n      don't load zephyr subscriptions\n");
732  fprintf(stderr, "  -d      enable debugging\n");
733  fprintf(stderr, "  -D      enable debugging and delete previous debug file\n");
734  fprintf(stderr, "  -v      print the Owl version number and exit\n");
735  fprintf(stderr, "  -h      print this help message\n");
736  fprintf(stderr, "  -c      specify an alternate config file\n");
737  fprintf(stderr, "  -t      set the tty name\n");
738}
739
740#if OWL_STDERR_REDIR
741
742/* Replaces stderr with a pipe so that we can read from it.
743 * Returns the fd of the pipe from which stderr can be read. */
744int stderr_replace(void)
745{
746  int pipefds[2];
747  if (0 != pipe(pipefds)) {
748    perror("pipe");
749    owl_function_debugmsg("stderr_replace: pipe FAILED\n");
750    return -1;
751  }
752    owl_function_debugmsg("stderr_replace: pipe: %d,%d\n", pipefds[0], pipefds[1]);
753  if (-1 == dup2(pipefds[1], 2 /*stderr*/)) {
754    owl_function_debugmsg("stderr_replace: dup2 FAILED (%s)\n", strerror(errno));
755    perror("dup2");
756    return -1;
757  }
758  return pipefds[0];
759}
760
761/* Sends stderr (read from rfd) messages to the error console */
762void stderr_redirect_handler(int handle, int rfd, int eventmask, void *data) 
763{
764  int navail, bread;
765  char *buf;
766  /*owl_function_debugmsg("stderr_redirect: called with rfd=%d\n", rfd);*/
767  if (rfd<0) return;
768  if (-1 == ioctl(rfd, FIONREAD, (void*)&navail)) {
769    return;
770  }
771  /*owl_function_debugmsg("stderr_redirect: navail = %d\n", navail);*/
772  if (navail<=0) return;
773  if (navail>256) { navail = 256; }
774  buf = owl_malloc(navail+1);
775  bread = read(rfd, buf, navail);
776  if (buf[navail-1] != '\0') {
777    buf[navail] = '\0';
778  }
779  owl_function_error("Err: %s", buf);
780  owl_free(buf);
781}
782
783#endif /* OWL_STDERR_REDIR */
Note: See TracBrowser for help on using the repository browser.