source: owl.c @ afbf668

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