source: owl.c @ 180cd15

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 180cd15 was 15b34fd, checked in by James M. Kretchmar <kretch@mit.edu>, 16 years ago
Fixed some small memory leaks in logging if files unwriteable If the variable logfilter is set it names a filter. Any messages matching this filter are logged. This is an independent mechanism from the other logging variables. If you want to control all logging with logfilter the other variables must be set to their default (off) settings. [BZ 37] Relatively substantial changes made under the hood to support filter logging. Now have more consistent interfaces to creating messages etc. Still needs more work though.
  • Property mode set to 100644
File size: 25.4 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#ifdef HAVE_LIBZEPHYR
141  /* zephyr init */
142  ret=owl_zephyr_initialize();
143  if (ret) {
144    exit(1);
145  }
146#endif
147 
148  /* signal handler */
149  /*sigact.sa_handler=sig_handler;*/
150  sigact.sa_sigaction=sig_handler;
151  sigemptyset(&sigact.sa_mask);
152  sigact.sa_flags=SA_SIGINFO;
153  sigaction(SIGWINCH, &sigact, NULL);
154  sigaction(SIGALRM, &sigact, NULL);
155  sigaction(SIGPIPE, &sigact, NULL);
156  sigaction(SIGTERM, &sigact, NULL);
157  sigaction(SIGHUP, &sigact, NULL);
158
159  /* save initial terminal settings */
160  tcgetattr(0, owl_global_get_startup_tio(&g));
161
162  /* turn ISTRIP off */
163  tcgetattr(0, &tio);
164  tio.c_iflag &= ~ISTRIP;
165  tcsetattr(0, TCSAFLUSH, &tio);
166
167  /* screen init */
168  if (!getenv("TERMINFO")) {
169    sprintf(buff, "TERMINFO=%s", TERMINFO);
170    putenv(buff);
171    owl_function_debugmsg("startup: setting TERMINFO to %s", TERMINFO);
172  } else {
173    owl_function_debugmsg("startup: leaving TERMINFO as %s from envrionment", getenv("TERMINFO"));
174  }
175  initscr();
176  start_color();
177#ifdef HAVE_USE_DEFAULT_COLORS
178  use_default_colors();
179#endif
180  raw();
181  noecho();
182
183  /* define simple color pairs */
184  if (has_colors() && COLOR_PAIRS>=8) {
185    init_pair(OWL_COLOR_BLACK,   COLOR_BLACK,   -1);
186    init_pair(OWL_COLOR_RED,     COLOR_RED,     -1);
187    init_pair(OWL_COLOR_GREEN,   COLOR_GREEN,   -1);
188    init_pair(OWL_COLOR_YELLOW,  COLOR_YELLOW,  -1);
189    init_pair(OWL_COLOR_BLUE,    COLOR_BLUE,    -1);
190    init_pair(OWL_COLOR_MAGENTA, COLOR_MAGENTA, -1);
191    init_pair(OWL_COLOR_CYAN,    COLOR_CYAN,    -1);
192    init_pair(OWL_COLOR_WHITE,   COLOR_WHITE,   -1);
193  }
194
195  /* owl global init */
196  owl_global_init(&g);
197  if (debug) owl_global_set_debug_on(&g);
198  owl_function_debugmsg("startup: first available debugging message");
199  owl_global_set_startupargs(&g, argcsave, argvsave);
200#ifdef HAVE_LIBZEPHYR
201  owl_global_set_havezephyr(&g);
202#endif
203  owl_global_set_haveaim(&g);
204
205#if OWL_STDERR_REDIR
206  /* Do this only after we've started curses up... */
207  owl_function_debugmsg("startup: doing stderr redirection");
208  newstderr = stderr_replace();
209  owl_muxevents_add(owl_global_get_muxevents(&g), newstderr, OWL_MUX_READ,
210                    stderr_redirect_handler, NULL);
211#endif   
212
213  /* create the owl directory, in case it does not exist */
214  owl_function_debugmsg("startup: creating owl directory, if not present");
215  dir=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_CONFIG_DIR);
216  mkdir(dir, S_IRWXU);
217  owl_free(dir);
218
219  /* set the tty, either from the command line, or by figuring it out */
220  owl_function_debugmsg("startup: setting tty name");
221  if (tty) {
222    owl_global_set_tty(&g, tty);
223  } else {
224    owl_global_set_tty(&g, owl_util_get_default_tty());
225  }
226
227  /* setup the built-in styles */
228  owl_function_debugmsg("startup: creating built-in styles");
229  s=owl_malloc(sizeof(owl_style));
230  owl_style_create_internal(s, "default", &owl_stylefunc_default,
231                            "Default message formatting");
232  owl_global_add_style(&g, s);
233
234  s=owl_malloc(sizeof(owl_style));
235  owl_style_create_internal(s, "basic", &owl_stylefunc_basic,
236                            "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,
241                            "VT message formatting.");
242  owl_global_add_style(&g, s);
243#endif
244  s=owl_malloc(sizeof(owl_style));
245  owl_style_create_internal(s, "oneline", &owl_stylefunc_oneline,
246                            "Formats for one-line-per-message");
247  owl_global_add_style(&g, s);
248
249  /* setup the default filters */
250  /* the personal filter will need to change again when AIM chat's are
251   *  included.  Also, there should be an %aimme% */
252  owl_function_debugmsg("startup: creating default filters");
253  f=owl_malloc(sizeof(owl_filter));
254  owl_filter_init_fromstring(f, "personal", "( type ^zephyr$ "
255                             "and class ^message$ and instance ^personal$ "
256                             "and ( recipient ^%me%$ or sender ^%me%$ ) ) "
257                             "or ( type ^aim$ and login ^none$ )");
258  owl_list_append_element(owl_global_get_filterlist(&g), f);
259
260  f=owl_malloc(sizeof(owl_filter));
261  owl_filter_init_fromstring(f, "trash", "class ^mail$ or opcode ^ping$ or type ^admin$ or ( not login ^none$ )");
262  owl_list_append_element(owl_global_get_filterlist(&g), f);
263
264  f=owl_malloc(sizeof(owl_filter));
265  owl_filter_init_fromstring(f, "ping", "opcode ^ping$");
266  owl_list_append_element(owl_global_get_filterlist(&g), f);
267
268  f=owl_malloc(sizeof(owl_filter));
269  owl_filter_init_fromstring(f, "auto", "opcode ^auto$");
270  owl_list_append_element(owl_global_get_filterlist(&g), f);
271
272  f=owl_malloc(sizeof(owl_filter));
273  owl_filter_init_fromstring(f, "login", "not login ^none$");
274  owl_list_append_element(owl_global_get_filterlist(&g), f);
275
276  f=owl_malloc(sizeof(owl_filter));
277  owl_filter_init_fromstring(f, "reply-lockout", "class ^noc or class ^mail$");
278  owl_list_append_element(owl_global_get_filterlist(&g), f);
279
280  f=owl_malloc(sizeof(owl_filter));
281  owl_filter_init_fromstring(f, "out", "direction ^out$");
282  owl_list_append_element(owl_global_get_filterlist(&g), f);
283
284  f=owl_malloc(sizeof(owl_filter));
285  owl_filter_init_fromstring(f, "aim", "type ^aim$");
286  owl_list_append_element(owl_global_get_filterlist(&g), f);
287
288  f=owl_malloc(sizeof(owl_filter));
289  owl_filter_init_fromstring(f, "zephyr", "type ^zephyr$");
290  owl_list_append_element(owl_global_get_filterlist(&g), f);
291
292  f=owl_malloc(sizeof(owl_filter));
293  owl_filter_init_fromstring(f, "none", "false");
294  owl_list_append_element(owl_global_get_filterlist(&g), f);
295
296  f=owl_malloc(sizeof(owl_filter));
297  owl_filter_init_fromstring(f, "all", "true");
298  owl_list_append_element(owl_global_get_filterlist(&g), f);
299
300  /* set the current view */
301  owl_function_debugmsg("startup: setting the current view");
302  owl_view_create(owl_global_get_current_view(&g), "main", f, owl_global_get_style_by_name(&g, "default"));
303
304  /* AIM init */
305  owl_function_debugmsg("startup: doing AIM initialization");
306  owl_aim_init();
307
308  /* process the startup file */
309  owl_function_debugmsg("startup: processing startup file");
310  owl_function_source(NULL);
311
312  /* read the config file */
313  owl_function_debugmsg("startup: processing config file");
314  owl_context_set_readconfig(owl_global_get_context(&g));
315  perlerr=owl_perlconfig_readconfig(configfile);
316  if (perlerr) {
317    endwin();
318    owl_function_error("Error parsing configfile: %s\n", perlerr);
319    fprintf(stderr, "\nError parsing configfile: %s\n", perlerr);
320    fflush(stderr);
321    printf("\nError parsing configfile: %s\n", perlerr);
322    fflush(stdout);
323    exit(1);
324  }
325
326  /* if the config defines a formatting function, add 'perl' as a style */
327  if (owl_global_is_config_format(&g)) {
328    owl_function_debugmsg("Found perl formatting");
329    s=owl_malloc(sizeof(owl_style));
330    owl_style_create_perl(s, "perl", "owl::_format_msg_legacy_wrap",
331                          "User-defined perl style that calls owl::format_msg"
332                          "with legacy global variable support");
333    owl_global_add_style(&g, s);
334    owl_global_set_default_style(&g, "perl");
335  }
336
337  /* execute the startup function in the configfile */
338  owl_function_debugmsg("startup: executing perl startup, if applicable");
339  perlout = owl_perlconfig_execute("owl::startup();");
340  if (perlout) owl_free(perlout);
341 
342  /* hold on to the window names for convenience */
343  msgwin=owl_global_get_curs_msgwin(&g);
344  recwin=owl_global_get_curs_recwin(&g);
345  sepwin=owl_global_get_curs_sepwin(&g);
346  typwin=owl_global_get_curs_typwin(&g);
347  tw=owl_global_get_typwin(&g);
348
349  /* welcome message */
350  owl_function_debugmsg("startup: creating splash message");
351  strcpy(startupmsg, "-----------------------------------------------------------------------\n");
352  sprintf(buff,      "Welcome to Owl version %s.  Press 'h' for on-line help. \n", OWL_VERSION_STRING);
353  strcat(startupmsg, buff);
354  strcat(startupmsg, "                                                                       \n");
355  strcat(startupmsg, "If you would like to receive release announcements about Owl you can   \n");
356  strcat(startupmsg, "join the owl-users mailing list at http://www.ktools.org/              \n");
357  strcat(startupmsg, "                                                                 ^ ^   \n");
358  strcat(startupmsg, "                                                                 OvO   \n");
359  strcat(startupmsg, "Please report any bugs or suggestions to bug-owl@ktools.org     (   )  \n");
360  strcat(startupmsg, "-----------------------------------------------------------------m-m---\n");
361  owl_function_adminmsg("", startupmsg);
362  sepbar(NULL);
363
364  wrefresh(sepwin);
365
366  /* load zephyr subs */
367  if (initialsubs) {
368    int ret2;
369    owl_function_debugmsg("startup: loading initial zephyr subs");
370
371    /* load default subscriptions */
372    ret=owl_zephyr_loaddefaultsubs();
373   
374    /* load subscriptions from subs file */
375    ret2=owl_zephyr_loadsubs(NULL, 0);
376
377    if (ret || ret2) {
378      owl_function_adminmsg("", "Error loading zephyr subscriptions");
379    } else if (ret2!=-1) {
380      owl_global_add_userclue(&g, OWL_USERCLUE_CLASSES);
381    }
382
383    /* load login subscriptions */
384    if (owl_global_is_loginsubs(&g)) {
385      owl_function_debugmsg("startup: loading login subs");
386      owl_function_loadloginsubs(NULL);
387    }
388  }
389
390  /* First buddy check to sync the list without notifications */
391  owl_function_debugmsg("startup: doing initial zephyr buddy check");
392  /* owl_function_zephyr_buddy_check(0); */
393
394  /* set the startup and default style, based on userclue and presence of a
395   * formatting function */
396  owl_function_debugmsg("startup: setting startup and default style");
397  if (0 != strcmp(owl_global_get_default_style(&g), "__unspecified__")) {
398    /* the style was set by the user: leave it alone */
399  } else if (owl_global_is_config_format(&g)) {
400    owl_global_set_default_style(&g, "perl");
401  } else if (owl_global_is_userclue(&g, OWL_USERCLUE_CLASSES)) {
402    owl_global_set_default_style(&g, "default");
403  } else {
404    owl_global_set_default_style(&g, "basic");
405  }
406
407  /* zlog in if we need to */
408  if (owl_global_is_startuplogin(&g)) {
409    owl_function_debugmsg("startup: doing zlog in");
410    owl_zephyr_zlog_in();
411  }
412
413  owl_function_debugmsg("startup: set style for the view");
414  owl_view_set_style(owl_global_get_current_view(&g), 
415                     owl_global_get_style_by_name(&g, owl_global_get_default_style(&g)));   
416
417  owl_function_debugmsg("startup: setting context interactive");
418  owl_context_set_interactive(owl_global_get_context(&g));
419
420  nexttimediff=10;
421  nexttime=time(NULL);
422
423  owl_function_debugmsg("startup: entering main loop");
424  /* main loop */
425  while (1) {
426
427    /* if a resize has been scheduled, deal with it */
428    owl_global_resize(&g, 0, 0);
429
430    /* these are here in case a resize changes the windows */
431    msgwin=owl_global_get_curs_msgwin(&g);
432    recwin=owl_global_get_curs_recwin(&g);
433    sepwin=owl_global_get_curs_sepwin(&g);
434    typwin=owl_global_get_curs_typwin(&g);
435
436    followlast=owl_global_should_followlast(&g);
437   
438    /* Do AIM stuff */
439    if (owl_global_is_doaimevents(&g)) {
440      owl_aim_process_events();
441
442      if (owl_global_is_aimloggedin(&g)) {
443        if (owl_timer_is_expired(owl_global_get_aim_buddyinfo_timer(&g))) {
444          /* owl_buddylist_request_idletimes(owl_global_get_buddylist(&g)); */
445          owl_timer_reset(owl_global_get_aim_buddyinfo_timer(&g));
446        }
447      }
448    }
449
450    /* little hack */
451    now=time(NULL);
452    today=localtime(&now);
453    if (today->tm_mon==9 && today->tm_mday==31 && owl_global_get_runtime(&g)<600) {
454      if (time(NULL)>nexttime) {
455        if (nexttimediff==1) {
456          nexttimediff=10;
457        } else {
458          nexttimediff=1;
459        }
460        nexttime+=nexttimediff;
461        owl_hack_animate();
462      }
463    }
464
465    /* Grab incoming messages. */
466    newmsgs=0;
467    zpendcount=0;
468    while(owl_zephyr_zpending() || owl_global_messagequeue_pending(&g)) {
469#ifdef HAVE_LIBZEPHYR
470      struct sockaddr_in from;
471#endif
472      owl_message *m=NULL;
473      owl_filter *f;
474
475      /* grab the new message, stick it in 'm' */
476      if (owl_zephyr_zpending()) {
477#ifdef HAVE_LIBZEPHYR
478        /* grab a zephyr notice, but if we've done 20 without stopping,
479           take a break to process keystrokes etc. */
480        if (zpendcount>20) break;
481        ZReceiveNotice(&notice, &from);
482        zpendcount++;
483       
484        /* is this an ack from a zephyr we sent? */
485        if (owl_zephyr_notice_is_ack(&notice)) {
486          owl_zephyr_handle_ack(&notice);
487          continue;
488        }
489       
490        /* if it's a ping and we're not viewing pings then skip it */
491        if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
492          continue;
493        }
494
495        /* create the new message */
496        m=owl_malloc(sizeof(owl_message));
497        owl_message_create_from_znotice(m, &notice);
498#endif
499      } else if (owl_global_messagequeue_pending(&g)) {
500        /* pick up the non-zephyr message in the message queue */
501        m=owl_global_messageuque_popmsg(&g);
502      } else {
503        /* Not supposed to happen, but we seem to get here on resizes */
504        owl_function_debugmsg("Bottomed out looking for zephyr");
505      }
506
507      /* If we didn't pick up a message for some reason, don't go on */
508      if (m==NULL) {
509        owl_function_debugmsg("m is null in main loop");
510        continue;
511      }
512     
513      /* if this message it on the puntlist, nuke it and continue */
514      if (owl_global_message_is_puntable(&g, m)) {
515        owl_message_free(m);
516        continue;
517      }
518
519      /*  login or logout that should be ignored? */
520      if (owl_global_is_ignorelogins(&g) && owl_message_is_loginout(m)) {
521        owl_message_free(m);
522        continue;
523      }
524
525      /* otherwise add it to the global list */
526      owl_messagelist_append_element(owl_global_get_msglist(&g), m);
527      newmsgs=1;
528
529      /* let the config know the new message has been received */
530      owl_perlconfig_getmsg(m, 0, NULL);
531
532      /* add it to any necessary views; right now there's only the current view */
533      owl_view_consider_message(owl_global_get_current_view(&g), m);
534
535      /* do we need to autoreply? */
536      if (owl_global_is_zaway(&g) && !owl_message_get_attribute_value(m, "isauto")) {
537        if (owl_message_is_type_zephyr(m)) {
538          owl_zephyr_zaway(m);
539        } else if (owl_message_is_type_aim(m)) {
540          if (owl_message_is_private(m)) {
541            owl_function_send_aimawymsg(owl_message_get_sender(m), owl_global_get_zaway_msg(&g));
542          }
543        }
544      }
545
546      /* ring the bell if it's a personal */
547      if (!strcmp(owl_global_get_personalbell(&g), "on")) {
548          if (!owl_message_is_loginout(m) &&
549              !owl_message_is_mail(m) &&
550              owl_message_is_private(m)) {
551            owl_function_beep();
552          }
553      } else if (!strcmp(owl_global_get_personalbell(&g), "off")) {
554        /* do nothing */
555      } else {
556        f=owl_global_get_filter(&g, owl_global_get_personalbell(&g));
557        if (f && owl_filter_message_match(f, m)) {
558          owl_function_beep();
559        }
560      }
561
562
563      /* if it matches the alert filter, do the alert action */
564      f=owl_global_get_filter(&g, owl_global_get_alert_filter(&g));
565      if (f && owl_filter_message_match(f, m)) {
566        owl_function_command(owl_global_get_alert_action(&g));
567      }
568
569      /* if it's a zephyr login or logout, update the zbuddylist */
570      if (owl_message_is_type_zephyr(m) && owl_message_is_loginout(m)) {
571        if (owl_message_is_login(m)) {
572          owl_zbuddylist_adduser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
573        } else if (owl_message_is_logout(m)) {
574          owl_zbuddylist_deluser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
575        } else {
576          owl_function_error("Internal error: received login notice that is neither login nor logout");
577        }
578      }
579
580      /* check for burning ears message */
581      /* this is an unsupported feature */
582      if (owl_global_is_burningears(&g) && owl_message_is_burningears(m)) {
583        char *buff;
584        buff = owl_sprintf("@i(Burning ears message on class %s)", owl_message_get_class(m));
585        owl_function_adminmsg(buff, "");
586        owl_free(buff);
587        owl_function_beep();
588      }
589
590      /* log the message if we need to */
591      owl_log_message(m);
592    }
593
594    /* is it time to check zbuddies? */
595    if (owl_global_is_pseudologins(&g)) {
596      if (owl_timer_is_expired(owl_global_get_zephyr_buddycheck_timer(&g))) {
597        owl_function_debugmsg("Doing zephyr buddy check");
598        owl_function_zephyr_buddy_check(1);
599        owl_timer_reset(owl_global_get_zephyr_buddycheck_timer(&g));
600      }
601    }
602
603    /* dispatch any muxevents */
604    owl_muxevents_dispatch(owl_global_get_muxevents(&g), 0);
605
606    /* follow the last message if we're supposed to */
607    if (newmsgs && followlast) {
608      owl_function_lastmsg_noredisplay();
609    }
610
611    /* do the newmsgproc thing */
612    if (newmsgs) {
613      owl_function_do_newmsgproc();
614    }
615   
616    /* redisplay if necessary */
617    /* this should be optimized to not run if the new messages won't be displayed */
618    if (newmsgs) {
619      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
620      sepbar(NULL);
621      if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
622        owl_popwin_refresh(owl_global_get_popwin(&g));
623        /* TODO: this is a broken kludge */
624        if (owl_global_get_viewwin(&g)) {
625          owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
626        }
627      }
628      owl_global_set_needrefresh(&g);
629    }
630
631    /* if a popwin just came up, refresh it */
632    pw=owl_global_get_popwin(&g);
633    if (owl_popwin_is_active(pw) && owl_popwin_needs_first_refresh(pw)) {
634      owl_popwin_refresh(pw);
635      owl_popwin_no_needs_first_refresh(pw);
636      owl_global_set_needrefresh(&g);
637      /* TODO: this is a broken kludge */
638      if (owl_global_get_viewwin(&g)) {
639        owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
640      }
641    }
642
643    /* update the terminal if we need to */
644    if (owl_global_is_needrefresh(&g)) {
645      /* leave the cursor in the appropriate window */
646      if (owl_global_is_typwin_active(&g)) {
647        owl_function_set_cursor(typwin);
648      } else {
649        owl_function_set_cursor(sepwin);
650      }
651      doupdate();
652      owl_global_set_noneedrefresh(&g);
653    }
654
655    /* Handle all keypresses.  If no key has been pressed, sleep for a
656     * little bit, but otherwise do not.  This lets input be grabbed
657     * as quickly as possbile */
658    j=wgetch(typwin);
659    if (j==ERR) {
660      usleep(10);
661    } else {
662      /* find and activate the current keymap.
663       * TODO: this should really get fixed by activating
664       * keymaps as we switch between windows...
665       */
666      if (pw && owl_popwin_is_active(pw) && owl_global_get_viewwin(&g)) {
667        owl_context_set_popless(owl_global_get_context(&g), 
668                                owl_global_get_viewwin(&g));
669        owl_function_activate_keymap("popless");
670      } else if (owl_global_is_typwin_active(&g) 
671                 && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_ONELINE) {
672        /*
673          owl_context_set_editline(owl_global_get_context(&g), tw);
674          owl_function_activate_keymap("editline");
675        */
676      } else if (owl_global_is_typwin_active(&g) 
677                 && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_MULTILINE) {
678        owl_context_set_editmulti(owl_global_get_context(&g), tw);
679        owl_function_activate_keymap("editmulti");
680      } else {
681        owl_context_set_recv(owl_global_get_context(&g));
682        owl_function_activate_keymap("recv");
683      }
684      /* now actually handle the keypress */
685      ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j);
686      if (ret!=0 && ret!=1) {
687        owl_function_makemsg("Unable to handle keypress");
688      }
689    }
690
691    /* Log any error signals */
692    {
693      siginfo_t si;
694      int signum;
695      if ((signum = owl_global_get_errsignal_and_clear(&g, &si)) > 0) {
696        owl_function_error("Got unexpected signal: %d %s  (code: %d band: %d  errno: %d)", 
697                           signum, signum==SIGPIPE?"SIGPIPE":"SIG????",
698                           si.si_code, si.si_band, si.si_errno);
699      }
700    }
701
702  }
703}
704
705void sig_handler(int sig, siginfo_t *si, void *data)
706{
707  if (sig==SIGWINCH) {
708    /* we can't inturrupt a malloc here, so it just sets a flag
709     * schedulding a resize for later
710     */
711    owl_function_resize();
712  } else if (sig==SIGPIPE || sig==SIGCHLD) {
713    /* Set a flag and some info that we got the sigpipe
714     * so we can record that we got it and why... */
715    owl_global_set_errsignal(&g, sig, si);
716  } else if (sig==SIGTERM || sig==SIGHUP) {
717    owl_function_quit();
718  }
719
720}
721
722void usage()
723{
724  fprintf(stderr, "Owl version %s\n", OWL_VERSION_STRING);
725  fprintf(stderr, "Usage: owl [-n] [-d] [-D] [-v] [-h] [-c <configfile>] [-t <ttyname>]\n");
726  fprintf(stderr, "  -n      don't load zephyr subscriptions\n");
727  fprintf(stderr, "  -d      enable debugging\n");
728  fprintf(stderr, "  -D      enable debugging and delete previous debug file\n");
729  fprintf(stderr, "  -v      print the Owl version number and exit\n");
730  fprintf(stderr, "  -h      print this help message\n");
731  fprintf(stderr, "  -c      specify an alternate config file\n");
732  fprintf(stderr, "  -t      set the tty name\n");
733}
734
735#if OWL_STDERR_REDIR
736
737/* Replaces stderr with a pipe so that we can read from it.
738 * Returns the fd of the pipe from which stderr can be read. */
739int stderr_replace(void)
740{
741  int pipefds[2];
742  if (0 != pipe(pipefds)) {
743    perror("pipe");
744    owl_function_debugmsg("stderr_replace: pipe FAILED\n");
745    return -1;
746  }
747    owl_function_debugmsg("stderr_replace: pipe: %d,%d\n", pipefds[0], pipefds[1]);
748  if (-1 == dup2(pipefds[1], 2 /*stderr*/)) {
749    owl_function_debugmsg("stderr_replace: dup2 FAILED (%s)\n", strerror(errno));
750    perror("dup2");
751    return -1;
752  }
753  return pipefds[0];
754}
755
756/* Sends stderr (read from rfd) messages to the error console */
757void stderr_redirect_handler(int handle, int rfd, int eventmask, void *data) 
758{
759  int navail, bread;
760  char *buf;
761  /*owl_function_debugmsg("stderr_redirect: called with rfd=%d\n", rfd);*/
762  if (rfd<0) return;
763  if (-1 == ioctl(rfd, FIONREAD, (void*)&navail)) {
764    return;
765  }
766  /*owl_function_debugmsg("stderr_redirect: navail = %d\n", navail);*/
767  if (navail<=0) return;
768  if (navail>256) { navail = 256; }
769  buf = owl_malloc(navail+1);
770  bread = read(rfd, buf, navail);
771  if (buf[navail-1] != '\0') {
772    buf[navail] = '\0';
773  }
774  owl_function_error("Err: %s", buf);
775  owl_free(buf);
776}
777
778#endif /* OWL_STDERR_REDIR */
Note: See TracBrowser for help on using the repository browser.