source: owl.c @ 5d9c664

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 5d9c664 was f1e629d, checked in by Erik Nygren <nygren@mit.edu>, 18 years ago
New API for perl message formatting functions. Legacy variables are still supported for owl::format_msg and owl::receive_msg, but these functions are now also passed an owl::Message object which contains methods for accessing the contents of the message. See perlwrap.pm (and docs TBD) for the available methods. *** WARNING: The exact API for owl::Message has *** not yet stabilized. Added "style" command for creating new styles. Usage: style <name> perl <function_name> Added support for "show styles". Changed global style table from list to dictionary. Changed AIM password prompt from "Password:" to "AIM Password:". Messages are reformatted after a window resize to allow styles to take into account the width of the window. When perl throws an error, the message is put in the msgwin if possible. Added perl functions for: owl::getcurmsg() -- returns an owl::Message object for the active message in the current view. owl::getnumcols() -- returns the column width of the window owl::zephyr_getrealm() -- returns the zephyr realm owl::zephyr_getsender() -- returns the zephyr sender Made owl::COMMAND("foo"); be syntactic sugar for owl::command("COMMAND foo"); *** Is this a good or bad idea? *** This feature may be taken out before release. Added perlwrap.pm to contain perl code to be compiled into the binary. This is transformed into perlwrap.c by encapsulate.pl. Renamed readconfig.c to perlconfig.c and changed variables accordingly. Minor bugfixes in cmd.c and commands.c
  • Property mode set to 100644
File size: 16.9 KB
Line 
1/*
2 * Copyright 2001 Massachusetts Institute of Technology
3 *
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that the above copyright notice and this
7 * permission notice appear in all copies and in supporting
8 * documentation.  No representation is made about the suitability of
9 * this software for any purpose.  It is provided "as is" without
10 * express or implied warranty.
11 */
12
13#include <stdio.h>
14#include <unistd.h>
15#include <stdlib.h>
16#include <string.h>
17#include <signal.h>
18#include <time.h>
19#include <sys/param.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include "owl.h"
23
24static const char fileIdent[] = "$Id$";
25
26owl_global g;
27
28int main(int argc, char **argv, char **env) {
29  WINDOW *recwin, *sepwin, *typwin, *msgwin;
30  owl_editwin *tw;
31  owl_popwin *pw;
32  int j, ret, initialsubs, debug, argcsave, followlast;
33  int newmsgs, zpendcount, nexttimediff;
34  struct sigaction sigact;
35  char *configfile, *tty, *perlout, *perlerr, **argvsave, buff[LINE], startupmsg[LINE];
36  owl_filter *f;
37  owl_style *s;
38  time_t nexttime, now;
39  struct tm *today;
40  char *dir;
41#ifdef HAVE_LIBZEPHYR
42  ZNotice_t notice;
43#endif
44
45  argcsave=argc;
46  argvsave=argv;
47  configfile=NULL;
48  tty=NULL;
49  debug=0;
50  initialsubs=1;
51  if (argc>0) {
52    argv++;
53    argc--;
54  }
55  while (argc>0) {
56    if (!strcmp(argv[0], "-n")) {
57      initialsubs=0;
58      argv++;
59      argc--;
60    } else if (!strcmp(argv[0], "-c")) {
61      if (argc<2) {
62        fprintf(stderr, "Too few arguments to -c\n");
63        usage();
64        exit(1);
65      }
66      configfile=argv[1];
67      argv+=2;
68      argc-=2;
69    } else if (!strcmp(argv[0], "-t")) {
70      if (argc<2) {
71        fprintf(stderr, "Too few arguments to -t\n");
72        usage();
73        exit(1);
74      }
75      tty=argv[1];
76      argv+=2;
77      argc-=2;
78    } else if (!strcmp(argv[0], "-d")) {
79      debug=1;
80      argv++;
81      argc--;
82    } else if (!strcmp(argv[0], "-v")) {
83      printf("This is owl version %s\n", OWL_VERSION_STRING);
84      exit(0);
85    } else {
86      fprintf(stderr, "Uknown argument\n");
87      usage();       
88      exit(1);
89    }
90  }
91
92#ifdef HAVE_LIBZEPHYR
93  /* zephyr init */
94  ret=owl_zephyr_initialize();
95  if (ret) {
96    exit(1);
97  }
98#endif
99 
100  /* signal handler */
101  sigact.sa_handler=sig_handler;
102  sigemptyset(&sigact.sa_mask);
103  sigact.sa_flags=0;
104  sigaction(SIGWINCH, &sigact, NULL);
105  sigaction(SIGALRM, &sigact, NULL);
106
107  /* screen init */
108  sprintf(buff, "TERMINFO=%s", TERMINFO);
109  putenv(buff);
110  initscr();
111  start_color();
112#ifdef HAVE_USE_DEFAULT_COLORS
113  use_default_colors();
114#endif
115  raw();
116  noecho();
117
118  /* define simple color pairs */
119  if (has_colors() && COLOR_PAIRS>=8) {
120    init_pair(OWL_COLOR_BLACK,   COLOR_BLACK,   -1);
121    init_pair(OWL_COLOR_RED,     COLOR_RED,     -1);
122    init_pair(OWL_COLOR_GREEN,   COLOR_GREEN,   -1);
123    init_pair(OWL_COLOR_YELLOW,  COLOR_YELLOW,  -1);
124    init_pair(OWL_COLOR_BLUE,    COLOR_BLUE,    -1);
125    init_pair(OWL_COLOR_MAGENTA, COLOR_MAGENTA, -1);
126    init_pair(OWL_COLOR_CYAN,    COLOR_CYAN,    -1);
127    init_pair(OWL_COLOR_WHITE,   COLOR_WHITE,   -1);
128  }
129
130   
131  /* owl global init */
132  owl_global_init(&g);
133  if (debug) owl_global_set_debug_on(&g);
134  owl_global_set_startupargs(&g, argcsave, argvsave);
135#ifdef HAVE_LIBZEPHYR
136  owl_global_set_havezephyr(&g);
137#endif
138  owl_global_set_haveaim(&g);
139 
140  /* create the owl directory, in case it does not exist */
141  dir=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_CONFIG_DIR);
142  mkdir(dir, S_IRWXU);
143  owl_free(dir);
144
145  /* set the tty, either from the command line, or by figuring it out */
146  if (tty) {
147    owl_global_set_tty(&g, tty);
148  } else {
149    owl_global_set_tty(&g, owl_util_get_default_tty());
150  }
151
152  /* setup the built-in styles */
153  s=owl_malloc(sizeof(owl_style));
154  owl_style_create_internal(s, "default", &owl_stylefunc_default,
155                            "Default message formatting");
156  owl_global_add_style(&g, s);
157
158  s=owl_malloc(sizeof(owl_style));
159  owl_style_create_internal(s, "basic", &owl_stylefunc_basic,
160                            "Basic message formatting.");
161  owl_global_add_style(&g, s);
162
163  s=owl_malloc(sizeof(owl_style));
164  owl_style_create_internal(s, "oneline", &owl_stylefunc_oneline,
165                            "Formats for one-line-per-message");
166  owl_global_add_style(&g, s);
167
168  /* setup the default filters */
169  /* the personal filter will need to change again when AIM chat's are
170   *  included.  Also, there should be an %aimme% */
171  f=owl_malloc(sizeof(owl_filter));
172  owl_filter_init_fromstring(f, "personal", "( type ^zephyr$ "
173                             "and class ^message$ and instance ^personal$ "
174                             "and ( recipient ^%me%$ or sender ^%me%$ ) ) "
175                             "or ( type ^aim$ and login ^none$ )");
176  owl_list_append_element(owl_global_get_filterlist(&g), f);
177
178  f=owl_malloc(sizeof(owl_filter));
179  owl_filter_init_fromstring(f, "trash", "class ^mail$ or opcode ^ping$ or type ^admin$ or ( not login ^none$ )");
180  owl_list_append_element(owl_global_get_filterlist(&g), f);
181
182  f=owl_malloc(sizeof(owl_filter));
183  owl_filter_init_fromstring(f, "ping", "opcode ^ping$");
184  owl_list_append_element(owl_global_get_filterlist(&g), f);
185
186  f=owl_malloc(sizeof(owl_filter));
187  owl_filter_init_fromstring(f, "auto", "opcode ^auto$");
188  owl_list_append_element(owl_global_get_filterlist(&g), f);
189
190  f=owl_malloc(sizeof(owl_filter));
191  owl_filter_init_fromstring(f, "login", "not login ^none$");
192  owl_list_append_element(owl_global_get_filterlist(&g), f);
193
194  f=owl_malloc(sizeof(owl_filter));
195  owl_filter_init_fromstring(f, "reply-lockout", "class ^noc or class ^mail$");
196  owl_list_append_element(owl_global_get_filterlist(&g), f);
197
198  f=owl_malloc(sizeof(owl_filter));
199  owl_filter_init_fromstring(f, "out", "direction ^out$");
200  owl_list_append_element(owl_global_get_filterlist(&g), f);
201
202  f=owl_malloc(sizeof(owl_filter));
203  owl_filter_init_fromstring(f, "aim", "type ^aim$");
204  owl_list_append_element(owl_global_get_filterlist(&g), f);
205
206  f=owl_malloc(sizeof(owl_filter));
207  owl_filter_init_fromstring(f, "zephyr", "type ^zephyr$");
208  owl_list_append_element(owl_global_get_filterlist(&g), f);
209
210  f=owl_malloc(sizeof(owl_filter));
211  owl_filter_init_fromstring(f, "none", "false");
212  owl_list_append_element(owl_global_get_filterlist(&g), f);
213
214  f=owl_malloc(sizeof(owl_filter));
215  owl_filter_init_fromstring(f, "all", "true");
216  owl_list_append_element(owl_global_get_filterlist(&g), f);
217
218  /* set the current view */
219  owl_view_create(owl_global_get_current_view(&g), "main", f, owl_global_get_style_by_name(&g, "default"));
220
221  /* AIM init */
222  owl_aim_init();
223
224  /* process the startup file */
225  owl_function_execstartup();
226
227  /* read the config file */
228  owl_context_set_readconfig(owl_global_get_context(&g));
229  perlerr=owl_perlconfig_readconfig(configfile);
230  if (perlerr) {
231    endwin();
232    fprintf(stderr, "\nError parsing configfile: %s\n", perlerr);
233    exit(1);
234  }
235
236  /* if the config defines a formatting function, add 'perl' as a style */
237  if (owl_global_is_config_format(&g)) {
238    owl_function_debugmsg("Found perl formatting");
239    s=owl_malloc(sizeof(owl_style));
240    owl_style_create_perl(s, "perl", "owl::_format_msg_legacy_wrap",
241                          "User-defined perl style that calls owl::format_msg"
242                          "with legacy global variable support");
243    owl_global_add_style(&g, s);
244    owl_global_set_default_style(&g, "perl");
245  }
246
247  /* set the startup and default style, based on userclue and presence of a
248   * formatting function */
249  if (owl_global_is_config_format(&g)) {
250    owl_global_set_default_style(&g, "perl");
251  } else if (owl_global_is_userclue(&g, OWL_USERCLUE_CLASSES)) {
252    owl_global_set_default_style(&g, "default");
253  } else {
254    owl_global_set_default_style(&g, "basic");
255  }
256
257  /* execute the startup function in the configfile */
258  perlout = owl_perlconfig_execute("owl::startup();");
259  if (perlout) owl_free(perlout);
260  owl_function_debugmsg("-- Owl Startup --");
261 
262  /* hold on to the window names for convenience */
263  msgwin=owl_global_get_curs_msgwin(&g);
264  recwin=owl_global_get_curs_recwin(&g);
265  sepwin=owl_global_get_curs_sepwin(&g);
266  typwin=owl_global_get_curs_typwin(&g);
267  tw=owl_global_get_typwin(&g);
268
269  wrefresh(sepwin);
270
271  /* load zephyr subs */
272  if (initialsubs) {
273    /* load normal subscriptions */
274    ret=owl_zephyr_loadsubs(NULL);
275    if (ret!=-1) {
276      owl_global_add_userclue(&g, OWL_USERCLUE_CLASSES);
277    }
278
279    /* load login subscriptions */
280    if (owl_global_is_loginsubs(&g)) {
281      owl_function_loadloginsubs(NULL);
282    }
283  }
284
285  /* zlog in if we need to */
286  if (owl_global_is_startuplogin(&g)) {
287    owl_zephyr_zlog_in();
288  }
289
290  owl_view_set_style(owl_global_get_current_view(&g), 
291                     owl_global_get_style_by_name(&g, owl_global_get_default_style(&g)));   
292
293  /* welcome message */
294  strcpy(startupmsg, "-------------------------------------------------------------------------\n");
295  sprintf(buff,      "Welcome to Owl version %s.  Press 'h' for on-line help. \n", OWL_VERSION_STRING);
296  strcat(startupmsg, buff);
297  strcat(startupmsg, "                                                                         \n");
298  strcat(startupmsg, "If you would like to receive release announcements about owl you can join \n");
299  strcat(startupmsg, "the owl-users@mit.edu mailing list.  MIT users can add themselves,       \n");
300  strcat(startupmsg, "otherwise send a request to owner-owl-users@mit.edu.               ^ ^   \n");
301  strcat(startupmsg, "                                                                   OvO   \n");
302  strcat(startupmsg, "Please report any bugs or suggestions to bug-owl@mit.edu          (   )  \n");
303  strcat(startupmsg, "-------------------------------------------------------------------m-m---\n");
304  owl_function_adminmsg("", startupmsg);
305  sepbar(NULL);
306 
307  owl_context_set_interactive(owl_global_get_context(&g));
308
309  nexttimediff=10;
310  nexttime=time(NULL);
311
312  /* main loop */
313  while (1) {
314
315    /* if a resize has been scheduled, deal with it */
316    owl_global_resize(&g, 0, 0);
317
318    /* these are here in case a resize changes the windows */
319    msgwin=owl_global_get_curs_msgwin(&g);
320    recwin=owl_global_get_curs_recwin(&g);
321    sepwin=owl_global_get_curs_sepwin(&g);
322    typwin=owl_global_get_curs_typwin(&g);
323
324    followlast=owl_global_should_followlast(&g);
325   
326    /* Do AIM stuff */
327    if (owl_global_is_doaimevents(&g)) {
328      owl_aim_process_events();
329
330      if (owl_global_is_aimloggedin(&g)) {
331        if (owl_timer_is_expired(owl_global_get_aim_buddyinfo_timer(&g))) {
332          owl_buddylist_request_idletimes(owl_global_get_buddylist(&g));
333          owl_timer_reset(owl_global_get_aim_buddyinfo_timer(&g));
334        }
335      }
336    }
337
338    /* little hack */
339    now=time(NULL);
340    today=localtime(&now);
341    if (today->tm_mon==9 && today->tm_mday==31 && owl_global_get_runtime(&g)<600) {
342      if (time(NULL)>nexttime) {
343        if (nexttimediff==1) {
344          nexttimediff=10;
345        } else {
346          nexttimediff=1;
347        }
348        nexttime+=nexttimediff;
349        owl_hack_animate();
350      }
351    }
352
353    /* Grab incoming messages. */
354    newmsgs=0;
355    zpendcount=0;
356    while(owl_zephyr_zpending() || owl_global_messagequeue_pending(&g)) {
357#ifdef HAVE_LIBZEPHYR
358      struct sockaddr_in from;
359#endif
360      owl_message *m=NULL;
361      owl_filter *f;
362
363      /* grab the new message, stick it in 'm' */
364      if (owl_zephyr_zpending()) {
365#ifdef HAVE_LIBZEPHYR
366        /* grab a zephyr notice, but if we've done 20 without stopping,
367           take a break to process keystrokes etc. */
368        if (zpendcount>20) break;
369        ZReceiveNotice(&notice, &from);
370        zpendcount++;
371       
372        /* is this an ack from a zephyr we sent? */
373        if (owl_zephyr_notice_is_ack(&notice)) {
374          owl_zephyr_handle_ack(&notice);
375          continue;
376        }
377       
378        /* if it's a ping and we're not viewing pings then skip it */
379        if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
380          continue;
381        }
382
383        /* create the new message */
384        m=owl_malloc(sizeof(owl_message));
385        owl_message_create_from_znotice(m, &notice);
386#endif
387      } else if (owl_global_messagequeue_pending(&g)) {
388        m=owl_global_messageuque_popmsg(&g);
389      }
390     
391      /* if this message it on the puntlist, nuke it and continue */
392      if (owl_global_message_is_puntable(&g, m)) {
393        owl_message_free(m);
394        continue;
395      }
396
397      /* otherwise add it to the global list */
398      owl_messagelist_append_element(owl_global_get_msglist(&g), m);
399      newmsgs=1;
400
401      /* let the config know the new message has been received */
402      owl_perlconfig_getmsg(m, 0, NULL);
403
404      /* add it to any necessary views; right now there's only the current view */
405      owl_view_consider_message(owl_global_get_current_view(&g), m);
406
407      /* do we need to autoreply? */
408      if (owl_message_is_type_zephyr(m) && owl_global_is_zaway(&g)) {
409        owl_zephyr_zaway(m);
410      }
411
412      /* ring the bell if it's a personal */
413      if (owl_global_is_personalbell(&g) &&
414          !owl_message_is_loginout(m) &&
415          !owl_message_is_mail(m) &&
416          owl_message_is_private(m)) {
417        owl_function_beep();
418      }
419
420      /* if it matches the alert filter, do the alert action */
421      f=owl_global_get_filter(&g, owl_global_get_alert_filter(&g));
422      if (f && owl_filter_message_match(f, m)) {
423        owl_function_command(owl_global_get_alert_action(&g));
424      }
425
426      /* check for burning ears message */
427      /* this is an unsupported feature */
428      if (owl_global_is_burningears(&g) && owl_message_is_burningears(m)) {
429        char *buff;
430        buff = owl_sprintf("@i(Burning ears message on class %s)", owl_message_get_class(m));
431        owl_function_adminmsg(buff, "");
432        owl_free(buff);
433        owl_function_beep();
434      }
435
436      /* log the message if we need to */
437      if (owl_global_is_logging(&g) || owl_global_is_classlogging(&g)) {
438        owl_log_incoming(m);
439      }
440    }
441
442    /* follow the last message if we're supposed to */
443    if (newmsgs && followlast) {
444      owl_function_lastmsg_noredisplay();
445    }
446
447    /* do the newmsgproc thing */
448    if (newmsgs) {
449      owl_function_do_newmsgproc();
450    }
451   
452    /* redisplay if necessary */
453    /* this should be optimized to not run if the new messages won't be displayed */
454    if (newmsgs) {
455      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
456      sepbar(NULL);
457      if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
458        owl_popwin_refresh(owl_global_get_popwin(&g));
459        /* TODO: this is a broken kludge */
460        if (owl_global_get_viewwin(&g)) {
461          owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
462        }
463      }
464      owl_global_set_needrefresh(&g);
465    }
466
467    /* if a popwin just came up, refresh it */
468    pw=owl_global_get_popwin(&g);
469    if (owl_popwin_is_active(pw) && owl_popwin_needs_first_refresh(pw)) {
470      owl_popwin_refresh(pw);
471      owl_popwin_no_needs_first_refresh(pw);
472      owl_global_set_needrefresh(&g);
473      /* TODO: this is a broken kludge */
474      if (owl_global_get_viewwin(&g)) {
475        owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
476      }
477    }
478
479    /* update the terminal if we need to */
480    if (owl_global_is_needrefresh(&g)) {
481      /* leave the cursor in the appropriate window */
482      if (owl_global_is_typwin_active(&g)) {
483        owl_function_set_cursor(typwin);
484      } else {
485        owl_function_set_cursor(sepwin);
486      }
487      doupdate();
488      owl_global_set_noneedrefresh(&g);
489    }
490
491    /* Handle all keypresses.  If no key has been pressed, sleep for a
492     * little bit, but otherwise do not.  This lets input be grabbed
493     * as quickly as possbile */
494    j=wgetch(typwin);
495    if (j==ERR) {
496      usleep(10);
497      continue;
498    }
499    /* find and activate the current keymap.
500     * TODO: this should really get fixed by activating
501     * keymaps as we switch between windows...
502     */
503    if (pw && owl_popwin_is_active(pw) && owl_global_get_viewwin(&g)) {
504      owl_context_set_popless(owl_global_get_context(&g), 
505                              owl_global_get_viewwin(&g));
506      owl_function_activate_keymap("popless");
507    } else if (owl_global_is_typwin_active(&g) 
508               && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_ONELINE) {
509      /*
510      owl_context_set_editline(owl_global_get_context(&g), tw);
511      owl_function_activate_keymap("editline");
512      */
513    } else if (owl_global_is_typwin_active(&g) 
514               && owl_editwin_get_style(tw)==OWL_EDITWIN_STYLE_MULTILINE) {
515      owl_context_set_editmulti(owl_global_get_context(&g), tw);
516      owl_function_activate_keymap("editmulti");
517    } else {
518      owl_context_set_recv(owl_global_get_context(&g));
519      owl_function_activate_keymap("recv");
520    }
521    /* now actually handle the keypress */
522    ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j);
523    if (ret!=0 && ret!=1) {
524      owl_function_makemsg("Unable to handle keypress");
525    }
526  }
527}
528
529void sig_handler(int sig) {
530  if (sig==SIGWINCH) {
531    /* we can't inturrupt a malloc here, so it just sets a flag
532     * schedulding a resize for later
533     */
534    owl_function_resize();
535  }
536}
537
538void usage() {
539  fprintf(stderr, "Owl version %s\n", OWL_VERSION_STRING);
540  fprintf(stderr, "Usage: owl [-n] [-d] [-v] [-h] [-c <configfile>] [-t <ttyname>]\n");
541  fprintf(stderr, "  -n      don't load zephyr subscriptions\n");
542  fprintf(stderr, "  -d      enable debugging\n");
543  fprintf(stderr, "  -v      print the Owl version number and exit\n");
544  fprintf(stderr, "  -h      print this help message\n");
545  fprintf(stderr, "  -c      specify an alternate config file\n");
546  fprintf(stderr, "  -t      set the tty name\n");
547 
548}
Note: See TracBrowser for help on using the repository browser.