source: functions.c @ 4c2ec6c

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 4c2ec6c was 0337203, checked in by Nelson Elhage <nelhage@mit.edu>, 18 years ago
First phase of the module rewrite. Internals now (IMO) somewhat cleaner. r19586@phanatique: nelhage | 2007-03-14 20:35:39 -0400 First pass at a cleaned up perlwrap.pm * Using a new hook style * Modules loaded by BarnOwl::ModuleLoader (not yet written) reload is unimplemented for now. If possible, I'd like it to live elsewhere. r19587@phanatique: nelhage | 2007-03-14 20:36:58 -0400 Switching to the new underscore internal hook names. r19592@phanatique: nelhage | 2007-03-16 00:34:00 -0400 Actually switch to _receive_msg r19593@phanatique: nelhage | 2007-03-16 00:34:27 -0400 Some minor cleanup of perlwrap.pm. Shoving fake entries into @INC. r19594@phanatique: nelhage | 2007-03-16 00:34:47 -0400 First revision of ModuleLoader.
  • Property mode set to 100644
File size: 99.6 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <signal.h>
5#include <netinet/in.h>
6#include <string.h>
7#include <time.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <sys/wait.h>
11#include <errno.h>
12#include <signal.h>
13#include "owl.h"
14
15static const char fileIdent[] = "$Id$";
16
17void owl_function_noop(void)
18{
19  return;
20}
21
22char *owl_function_command(char *cmdbuff)
23{
24  owl_function_debugmsg("executing command: %s", cmdbuff);
25  return owl_cmddict_execute(owl_global_get_cmddict(&g), 
26                             owl_global_get_context(&g), cmdbuff);
27}
28
29void owl_function_command_norv(char *cmdbuff)
30{
31  char *rv;
32  rv=owl_function_command(cmdbuff);
33  if (rv) owl_free(rv);
34}
35
36void owl_function_command_alias(char *alias_from, char *alias_to)
37{
38  owl_cmddict_add_alias(owl_global_get_cmddict(&g), alias_from, alias_to);
39}
40
41owl_cmd *owl_function_get_cmd(char *name)
42{
43  return owl_cmddict_find(owl_global_get_cmddict(&g), name);
44}
45
46void owl_function_show_commands()
47{
48  owl_list l;
49  owl_fmtext fm;
50
51  owl_fmtext_init_null(&fm);
52  owl_fmtext_append_bold(&fm, "Commands:  ");
53  owl_fmtext_append_normal(&fm, "(use 'show command <name>' for details)\n");
54  owl_cmddict_get_names(owl_global_get_cmddict(&g), &l);
55  owl_fmtext_append_list(&fm, &l, "\n", owl_function_cmd_describe);
56  owl_fmtext_append_normal(&fm, "\n");
57  owl_function_popless_fmtext(&fm);
58  owl_cmddict_namelist_free(&l);
59  owl_fmtext_free(&fm);
60}
61
62void owl_function_show_view(char *viewname)
63{
64  owl_view *v;
65  owl_fmtext fm;
66
67  /* we only have the one view right now */
68  v=owl_global_get_current_view(&g);
69  if (viewname && strcmp(viewname, owl_view_get_name(v))) {
70    owl_function_error("No view named '%s'", viewname);
71    return;
72  }
73
74  owl_fmtext_init_null(&fm);
75  owl_view_to_fmtext(v, &fm);
76  owl_function_popless_fmtext(&fm);
77  owl_fmtext_free(&fm);
78}
79
80void owl_function_show_styles() {
81  owl_list l;
82  owl_fmtext fm;
83
84  owl_fmtext_init_null(&fm);
85  owl_fmtext_append_bold(&fm, "Styles:\n");
86  owl_global_get_style_names(&g, &l);
87  owl_fmtext_append_list(&fm, &l, "\n", owl_function_style_describe);
88  owl_fmtext_append_normal(&fm, "\n");
89  owl_function_popless_fmtext(&fm);
90  owl_list_free_all(&l, owl_free);
91  owl_fmtext_free(&fm);
92}
93
94char *owl_function_style_describe(void *name) {
95  char *desc, *s;
96  owl_style *style;
97  style = owl_global_get_style_by_name(&g, name);
98  if (style) {
99    desc = owl_style_get_description(style);
100  } else {
101    desc = "???";
102  }
103  s = owl_sprintf("%-20s - %s%s", name, 
104                  0==owl_style_validate(style)?"":"[INVALID] ",
105                  desc);
106  return s;
107}
108
109char *owl_function_cmd_describe(void *name)
110{
111  owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
112  if (cmd) return owl_cmd_describe(cmd);
113  else return(NULL);
114}
115
116void owl_function_show_command(char *name)
117{
118  owl_function_help_for_command(name);
119}
120
121void owl_function_show_license()
122{
123  char *text;
124
125  text=""
126    "Owl version " OWL_VERSION_STRING "\n"
127    "Copyright (c) 2004 James Kretchmar. All rights reserved.\n"
128    "\n"
129    "Redistribution and use in source and binary forms, with or without\n"
130    "modification, are permitted provided that the following conditions are\n"
131    "met:\n"
132    "\n"
133    "   * Redistributions of source code must retain the above copyright\n"
134    "     notice, this list of conditions and the following disclaimer.\n"
135    "\n"
136    "   * Redistributions in binary form must reproduce the above copyright\n"
137    "     notice, this list of conditions and the following disclaimer in\n"
138    "     the documentation and/or other materials provided with the\n"
139    "     distribution.\n"
140    "\n"
141    "   * Redistributions in any form must be accompanied by information on\n"
142    "     how to obtain complete source code for the Owl software and any\n"
143    "     accompanying software that uses the Owl software. The source code\n"
144    "     must either be included in the distribution or be available for no\n"
145    "     more than the cost of distribution plus a nominal fee, and must be\n"
146    "     freely redistributable under reasonable conditions. For an\n"
147    "     executable file, complete source code means the source code for\n"
148    "     all modules it contains. It does not include source code for\n"
149    "     modules or files that typically accompany the major components of\n"
150    "     the operating system on which the executable file runs.\n"
151    "\n"
152    "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
153    "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
154    "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR\n"
155    "NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE\n"
156    "LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
157    "CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
158    "SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n"
159    "BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n"
160    "WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n"
161    "OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n"
162    "IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n";
163  owl_function_popless_text(text);
164}
165
166
167/* Add the given message to Owl's internal queue.  If displayoutgoing
168 * is disabled, the message is NOT added to any internal queue, -1 is
169 * returned and THE CALLER IS EXPECTED TO FREE THE GIVEN MESSAGE.
170 * Otherwise 0 is returned and the caller need do nothing more
171 */
172int owl_function_add_message(owl_message *m)
173{
174  /* if displayoutgoing is disabled, nuke the message and move on */
175  if (! owl_global_is_displayoutgoing(&g)) {
176    return(-1);
177  }
178
179  /* add it to the global list and current view */
180  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
181  owl_view_consider_message(owl_global_get_current_view(&g), m);
182
183  /* do followlast if necessary */
184  if (owl_global_should_followlast(&g)) owl_function_lastmsg_noredisplay();
185
186  /* redisplay etc. */
187  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
188  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
189    owl_popwin_refresh(owl_global_get_popwin(&g));
190  }
191  wnoutrefresh(owl_global_get_curs_recwin(&g));
192  owl_global_set_needrefresh(&g);
193  return(0);
194}
195
196/* Create an admin message, append it to the global list of messages
197 * and redisplay if necessary.
198 */
199void owl_function_adminmsg(char *header, char *body)
200{
201  owl_message *m;
202
203  m=owl_malloc(sizeof(owl_message));
204  owl_message_create_admin(m, header, body);
205 
206  /* add it to the global list and current view */
207  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
208  owl_view_consider_message(owl_global_get_current_view(&g), m);
209
210  /* do followlast if necessary */
211  if (owl_global_should_followlast(&g)) owl_function_lastmsg_noredisplay();
212
213  /* redisplay etc. */
214  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
215  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
216    owl_popwin_refresh(owl_global_get_popwin(&g));
217  }
218  wnoutrefresh(owl_global_get_curs_recwin(&g));
219  owl_global_set_needrefresh(&g);
220}
221
222/* Create an outgoing zephyr message and return a pointer to it.  Does
223 * not put it on the global queue, use owl_function_add_message() for
224 * that.
225 */
226owl_message *owl_function_make_outgoing_zephyr(char *body, char *zwriteline, char *zsig)
227{
228  owl_message *m;
229  owl_zwrite z;
230 
231  /* create a zwrite for the purpose of filling in other message fields */
232  owl_zwrite_create_from_line(&z, zwriteline);
233
234  /* create the message */
235  m=owl_malloc(sizeof(owl_message));
236  owl_message_create_from_zwriteline(m, zwriteline, body, zsig);
237  owl_zwrite_free(&z);
238
239  return(m);
240}
241
242/* Create an outgoing AIM message, returns a pointer to the created
243 * message or NULL if we're not logged into AIM (and thus unable to
244 * create the message).  Does not put it on the global queue.  Use
245 * owl_function_add_message() for that .
246 */
247owl_message *owl_function_make_outgoing_aim(char *body, char *to)
248{
249  owl_message *m;
250
251  /* error if we're not logged into aim */
252  if (!owl_global_is_aimloggedin(&g)) return(NULL);
253 
254  m=owl_malloc(sizeof(owl_message));
255  owl_message_create_aim(m,
256                         owl_global_get_aim_screenname(&g),
257                         to,
258                         body,
259                         OWL_MESSAGE_DIRECTION_OUT,
260                         0);
261  return(m);
262}
263
264/* Create an outgoing loopback message and return a pointer to it.
265 * Does not append it to the global queue, use
266 * owl_function_add_message() for that.
267 */
268owl_message *owl_function_make_outgoing_loopback(char *body)
269{
270  owl_message *m;
271
272  /* create the message */
273  m=owl_malloc(sizeof(owl_message));
274  owl_message_create_loopback(m, body);
275  owl_message_set_direction_out(m);
276
277  return(m);
278}
279
280void owl_function_zwrite_setup(char *line)
281{
282  owl_editwin *e;
283  char buff[1024];
284  owl_zwrite z;
285  int ret;
286
287  /* check the arguments */
288  ret=owl_zwrite_create_from_line(&z, line);
289  if (ret) {
290    owl_function_error("Error in zwrite arugments");
291    owl_zwrite_free(&z);
292    return;
293  }
294
295  /* send a ping if necessary */
296  if (owl_global_is_txping(&g)) {
297    owl_zwrite_send_ping(&z);
298  }
299  owl_zwrite_free(&z);
300
301  /* create and setup the editwin */
302  e=owl_global_get_typwin(&g);
303  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
304
305  if (!owl_global_get_lockout_ctrld(&g)) {
306    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
307  } else {
308    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
309  }
310
311  owl_editwin_clear(e);
312  owl_editwin_set_dotsend(e);
313  strcpy(buff, "----> ");
314  strcat(buff, line);
315  strcat(buff, "\n");
316  owl_editwin_set_locktext(e, buff);
317
318  /* make it active */
319  owl_global_set_typwin_active(&g);
320
321  owl_global_set_buffercommand(&g, line);
322  owl_global_set_buffercallback(&g, &owl_callback_zwrite);
323}
324
325void owl_function_aimwrite_setup(char *line)
326{
327  owl_editwin *e;
328  char buff[1024];
329
330  /* check the arguments */
331
332  /* create and setup the editwin */
333  e=owl_global_get_typwin(&g);
334  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
335
336  if (!owl_global_get_lockout_ctrld(&g)) {
337    owl_function_makemsg("Type your message below.  End with ^D or a dot on a line by itself.  ^C will quit.");
338  } else {
339    owl_function_makemsg("Type your message below.  End with a dot on a line by itself.  ^C will quit.");
340  }
341
342  owl_editwin_clear(e);
343  owl_editwin_set_dotsend(e);
344  strcpy(buff, "----> ");
345  strcat(buff, line);
346  strcat(buff, "\n");
347  owl_editwin_set_locktext(e, buff);
348
349  /* make it active */
350  owl_global_set_typwin_active(&g);
351
352  owl_global_set_buffercommand(&g, line);
353  owl_global_set_buffercallback(&g, &owl_callback_aimwrite);
354}
355
356void owl_function_loopwrite_setup()
357{
358  owl_editwin *e;
359
360  /* create and setup the editwin */
361  e=owl_global_get_typwin(&g);
362  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
363
364  if (!owl_global_get_lockout_ctrld(&g)) {
365    owl_function_makemsg("Type your message below.  End with ^D or a dot on a line by itself.  ^C will quit.");
366  } else {
367    owl_function_makemsg("Type your message below.  End with a dot on a line by itself.  ^C will quit.");
368  }
369
370  owl_editwin_clear(e);
371  owl_editwin_set_dotsend(e);
372  owl_editwin_set_locktext(e, "----> loopwrite\n");
373
374  /* make it active */
375  owl_global_set_typwin_active(&g);
376
377  owl_global_set_buffercommand(&g, "loopwrite");
378  owl_global_set_buffercallback(&g, &owl_callback_loopwrite);
379}
380
381void owl_callback_zwrite(owl_editwin *e) {
382  owl_function_zwrite(owl_editwin_get_command(e),
383                      owl_editwin_get_text(e));
384}
385
386/* send, log and display an outgoing zephyr.  If 'msg' is NULL
387 * the message is expected to be set from the zwrite line itself
388 */
389void owl_function_zwrite(char *line, char *msg)
390{
391  owl_zwrite z;
392  char *mymsg;
393  owl_message *m;
394
395  if(!strncmp(line, "zcrypt", strlen("zcrypt"))) {
396    owl_function_zcrypt(line, msg);
397    return;
398  }
399
400  /* create the zwrite and send the message */
401  owl_zwrite_create_from_line(&z, line);
402  if (msg) {
403    owl_zwrite_set_message(&z, msg);
404  }
405  owl_zwrite_send_message(&z);
406  owl_function_makemsg("Waiting for ack...");
407
408  /* If it's personal */
409  if (owl_zwrite_is_personal(&z)) {
410    /* create the outgoing message */
411    mymsg=owl_zwrite_get_message(&z);
412    m=owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
413
414    if (m) {
415      /* log it */
416      owl_log_message(m);
417     
418      /* add it or nuke it */
419      if (owl_global_is_displayoutgoing(&g)) {
420        owl_function_add_message(m);
421      } else {
422        owl_message_free(m);
423      }
424    } else {
425      owl_function_error("Could not create outgoing zephyr message");
426    }
427  }
428
429  /* free the zwrite */
430  owl_zwrite_free(&z);
431}
432
433/* send, log and display an outgoing zcrypt zephyr.  If 'msg' is NULL
434 * the message is expected to be set from the zwrite line itself
435 */
436void owl_function_zcrypt(char *line, char *msg)
437{
438  owl_zwrite z;
439  char *mymsg;
440  char *cryptmsg;
441  owl_message *m;
442#ifdef OWL_ENABLE_ZCRYPT
443  int ret;
444#endif
445
446  /* create the zwrite and send the message */
447  owl_zwrite_create_from_line(&z, line);
448  if (msg) {
449    owl_zwrite_set_message(&z, msg);
450  }
451
452  mymsg=owl_zwrite_get_message(&z);
453#ifdef OWL_ENABLE_ZCRYPT
454  cryptmsg=owl_malloc(strlen(mymsg)*4);
455  ret=owl_zcrypt_encrypt(cryptmsg, mymsg, owl_zwrite_get_class(&z), owl_zwrite_get_instance(&z));
456  if (ret) {
457    owl_function_error("Error in zcrypt, possibly no key found.  Message not sent.");
458    owl_function_beep();
459    owl_free(cryptmsg);
460    return;
461  }
462#else
463  cryptmsg=owl_strdup(mymsg);
464#endif
465
466  owl_zwrite_set_message(&z, cryptmsg);
467  owl_zwrite_set_opcode(&z, "crypt");
468  mymsg=cryptmsg;
469   
470  owl_zwrite_send_message(&z);
471  owl_function_makemsg("Waiting for ack...");
472
473  /* If it's personal */
474  if (owl_zwrite_is_personal(&z)) {
475    /* create the outgoing message */
476    mymsg=owl_zwrite_get_message(&z);
477    m=owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
478    if (m) {
479      /* log it */
480      owl_log_message(m);
481     
482      /* add it or nuke it */
483      if (owl_global_is_displayoutgoing(&g)) {
484        owl_function_add_message(m);
485      } else {
486        owl_message_free(m);
487      }
488    } else {
489      owl_function_error("Could not create outgoing zephyr message");
490    }
491  }
492
493  /* free the zwrite */
494  owl_free(cryptmsg);
495  owl_zwrite_free(&z);
496}
497
498void owl_callback_aimwrite(owl_editwin *e) {
499  owl_function_aimwrite(owl_editwin_get_command(e),
500                        owl_editwin_get_text(e));
501}
502
503void owl_function_aimwrite(char *line, char *msg)
504{
505  int ret;
506  char *to, *format_msg;
507  owl_message *m;
508
509  to = line + 9;
510
511  /* make a formatted copy of the message */
512  format_msg=owl_strdup(msg);
513  owl_text_wordunwrap(format_msg);
514 
515  /* send the message */
516  ret=owl_aim_send_im(to, format_msg);
517  if (!ret) {
518    owl_function_makemsg("AIM message sent.");
519  } else {
520    owl_function_error("Could not send AIM message.");
521  }
522
523  /* create the outgoing message */
524  m=owl_function_make_outgoing_aim(msg, to);
525
526  if (m) {
527    /* log it */
528    owl_log_message(m);
529   
530    /* display it or nuke it */
531    if (owl_global_is_displayoutgoing(&g)) {
532      owl_function_add_message(m);
533    } else {
534      owl_message_free(m);
535    }
536  } else {
537    owl_function_error("Could not create outgoing AIM message");
538  }
539
540  owl_free(format_msg);
541}
542
543void owl_function_send_aimawymsg(char *to, char *msg)
544{
545  int ret;
546  char *format_msg;
547  owl_message *m;
548
549  /* make a formatted copy of the message */
550  format_msg=owl_strdup(msg);
551  owl_text_wordunwrap(format_msg);
552 
553  /* send the message */
554  ret=owl_aim_send_awaymsg(to, format_msg);
555  if (!ret) {
556    /* owl_function_makemsg("AIM message sent."); */
557  } else {
558    owl_function_error("Could not send AIM message.");
559  }
560
561  /* create the message */
562  m=owl_function_make_outgoing_aim(msg, to);
563  if (m) {
564    /* log it */
565    owl_log_message(m);
566
567    /* display it or nuke it */
568    if (owl_global_is_displayoutgoing(&g)) {
569      owl_function_add_message(m);
570    } else {
571      owl_message_free(m);
572    }
573  } else {
574    owl_function_error("Could not create AIM message");
575  }
576  owl_free(format_msg);
577}
578
579void owl_callback_loopwrite(owl_editwin *e) {
580  owl_function_loopwrite(owl_editwin_get_text(e));
581}
582
583void owl_function_loopwrite(char *msg)
584{
585  owl_message *min, *mout;
586
587  /* create a message and put it on the message queue.  This simulates
588   * an incoming message */
589  min=owl_malloc(sizeof(owl_message));
590  owl_message_create_loopback(min, msg);
591  owl_message_set_direction_in(min);
592  owl_global_messagequeue_addmsg(&g, min);
593
594  mout=owl_function_make_outgoing_loopback(msg);
595  owl_log_message(mout);
596  if (owl_global_is_displayoutgoing(&g)) {
597    owl_function_add_message(mout);
598  } else {
599    owl_message_free(mout);
600  }
601
602  /* fake a makemsg */
603  owl_function_makemsg("loopback message sent");
604}
605
606/* If filter is non-null, looks for the next message matching
607 * that filter.  If skip_deleted, skips any deleted messages.
608 * If last_if_none, will stop at the last message in the view
609 * if no matching messages are found.  */
610void owl_function_nextmsg_full(char *filter, int skip_deleted, int last_if_none)
611{
612  int curmsg, i, viewsize, found;
613  owl_view *v;
614  owl_filter *f = NULL;
615  owl_message *m;
616
617  v=owl_global_get_current_view(&g);
618
619  if (filter) {
620    f=owl_global_get_filter(&g, filter);
621    if (!f) {
622      owl_function_error("No %s filter defined", filter);
623      return;
624    }
625  }
626
627  curmsg=owl_global_get_curmsg(&g);
628  viewsize=owl_view_get_size(v);
629  found=0;
630
631  /* just check to make sure we're in bounds... */
632  if (curmsg>viewsize-1) curmsg=viewsize-1;
633  if (curmsg<0) curmsg=0;
634
635  for (i=curmsg+1; i<viewsize; i++) {
636    m=owl_view_get_element(v, i);
637    if (skip_deleted && owl_message_is_delete(m)) continue;
638    if (f && !owl_filter_message_match(f, m)) continue;
639    found = 1;
640    break;
641  }
642
643  if (i>owl_view_get_size(v)-1) i=owl_view_get_size(v)-1;
644
645  if (!found) {
646    owl_function_makemsg("already at last%s message%s%s",
647                         skip_deleted?" non-deleted":"",
648                         filter?" in ":"", filter?filter:"");
649    /* if (!skip_deleted) owl_function_beep(); */
650  }
651
652  if (last_if_none || found) {
653    owl_global_set_curmsg(&g, i);
654    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
655    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
656    owl_global_set_direction_downwards(&g);
657  }
658}
659
660void owl_function_prevmsg_full(char *filter, int skip_deleted, int first_if_none)
661{
662  int curmsg, i, viewsize, found;
663  owl_view *v;
664  owl_filter *f = NULL;
665  owl_message *m;
666
667  v=owl_global_get_current_view(&g);
668
669  if (filter) {
670    f=owl_global_get_filter(&g, filter);
671    if (!f) {
672      owl_function_error("No %s filter defined", filter);
673      return;
674    }
675  }
676
677  curmsg=owl_global_get_curmsg(&g);
678  viewsize=owl_view_get_size(v);
679  found=0;
680
681  /* just check to make sure we're in bounds... */
682  if (curmsg<0) curmsg=0;
683
684  for (i=curmsg-1; i>=0; i--) {
685    m=owl_view_get_element(v, i);
686    if (skip_deleted && owl_message_is_delete(m)) continue;
687    if (f && !owl_filter_message_match(f, m)) continue;
688    found = 1;
689    break;
690  }
691
692  if (i<0) i=0;
693
694  if (!found) {
695    owl_function_makemsg("already at first%s message%s%s",
696                         skip_deleted?" non-deleted":"",
697                         filter?" in ":"", filter?filter:"");
698    /* if (!skip_deleted) owl_function_beep(); */
699  }
700
701  if (first_if_none || found) {
702    owl_global_set_curmsg(&g, i);
703    owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
704    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
705    owl_global_set_direction_upwards(&g);
706  }
707}
708
709void owl_function_nextmsg()
710{
711  owl_function_nextmsg_full(NULL, 0, 1);
712}
713
714void owl_function_prevmsg()
715{
716  owl_function_prevmsg_full(NULL, 0, 1);
717}
718
719void owl_function_nextmsg_notdeleted()
720{
721  owl_function_nextmsg_full(NULL, 1, 1);
722}
723
724void owl_function_prevmsg_notdeleted()
725{
726  owl_function_prevmsg_full(NULL, 1, 1);
727}
728
729void owl_function_nextmsg_personal()
730{
731  owl_function_nextmsg_full("personal", 0, 0);
732}
733
734void owl_function_prevmsg_personal()
735{
736  owl_function_prevmsg_full("personal", 0, 0);
737}
738
739
740/* if move_after is 1, moves after the delete */
741void owl_function_deletecur(int move_after)
742{
743  int curmsg;
744  owl_view *v;
745
746  v=owl_global_get_current_view(&g);
747
748  /* bail if there's no current message */
749  if (owl_view_get_size(v) < 1) {
750    owl_function_error("No current message to delete");
751    return;
752  }
753
754  /* mark the message for deletion */
755  curmsg=owl_global_get_curmsg(&g);
756  owl_view_delete_element(v, curmsg);
757
758  if (move_after) {
759    /* move the poiner in the appropriate direction
760     * to the next undeleted msg */
761    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
762      owl_function_prevmsg_notdeleted();
763    } else {
764      owl_function_nextmsg_notdeleted();
765    }
766  }
767}
768
769void owl_function_undeletecur(int move_after)
770{
771  int curmsg;
772  owl_view *v;
773
774  v=owl_global_get_current_view(&g);
775 
776  if (owl_view_get_size(v) < 1) {
777    owl_function_error("No current message to undelete");
778    return;
779  }
780  curmsg=owl_global_get_curmsg(&g);
781
782  owl_view_undelete_element(v, curmsg);
783
784  if (move_after) {
785    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
786      if (curmsg>0) {
787        owl_function_prevmsg();
788      } else {
789        owl_function_nextmsg();
790      }
791    } else {
792      owl_function_nextmsg();
793    }
794  }
795
796  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
797}
798
799void owl_function_expunge()
800{
801  int curmsg;
802  owl_message *m;
803  owl_messagelist *ml;
804  owl_view *v;
805  int lastmsgid=0;
806
807  curmsg=owl_global_get_curmsg(&g);
808  v=owl_global_get_current_view(&g);
809  ml=owl_global_get_msglist(&g);
810
811  m=owl_view_get_element(v, curmsg);
812  if (m) lastmsgid = owl_message_get_id(m);
813
814  /* expunge the message list */
815  owl_messagelist_expunge(ml);
816
817  /* update all views (we only have one right now) */
818  owl_view_recalculate(v);
819
820  /* find where the new position should be
821     (as close as possible to where we last where) */
822  curmsg = owl_view_get_nearest_to_msgid(v, lastmsgid);
823  if (curmsg>owl_view_get_size(v)-1) curmsg = owl_view_get_size(v)-1;
824  if (curmsg<0) curmsg = 0;
825  owl_global_set_curmsg(&g, curmsg);
826  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
827  /* if there are no messages set the direction to down in case we
828     delete everything upwards */
829  owl_global_set_direction_downwards(&g);
830 
831  owl_function_makemsg("Messages expunged");
832  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
833}
834
835void owl_function_firstmsg()
836{
837  owl_global_set_curmsg(&g, 0);
838  owl_global_set_topmsg(&g, 0);
839  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
840  owl_global_set_direction_downwards(&g);
841}
842
843void owl_function_lastmsg_noredisplay()
844{
845  int oldcurmsg, curmsg;
846  owl_view *v;
847
848  v=owl_global_get_current_view(&g);
849  oldcurmsg=owl_global_get_curmsg(&g);
850  curmsg=owl_view_get_size(v)-1; 
851  if (curmsg<0) curmsg=0;
852  owl_global_set_curmsg(&g, curmsg);
853  if (oldcurmsg < curmsg) {
854    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
855  } else if (curmsg<owl_view_get_size(v)) {
856    /* If already at the end, blank the screen and move curmsg
857     * past the end of the messages. */
858    owl_global_set_topmsg(&g, curmsg+1);
859    owl_global_set_curmsg(&g, curmsg+1);
860  } 
861  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
862  owl_global_set_direction_downwards(&g);
863}
864
865void owl_function_lastmsg()
866{
867  owl_function_lastmsg_noredisplay();
868  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
869}
870
871void owl_function_shift_right()
872{
873  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
874  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
875  owl_global_set_needrefresh(&g);
876}
877
878void owl_function_shift_left()
879{
880  int shift;
881
882  shift=owl_global_get_rightshift(&g);
883  if (shift>=10) {
884    owl_global_set_rightshift(&g, shift-10);
885    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
886    owl_global_set_needrefresh(&g);
887  } else {
888    owl_function_beep();
889    owl_function_makemsg("Already full left");
890  }
891}
892
893void owl_function_unsuball()
894{
895  unsuball();
896  owl_function_makemsg("Unsubscribed from all messages.");
897}
898
899
900/* Load zephyr subscriptions from the named 'file' and load zephyr's
901 * default subscriptions as well.  An error message is printed if
902 * 'file' can't be opened or if zephyr reports an error in
903 * subscribing.
904 *
905 * If 'file' is NULL, this look for the default filename
906 * $HOME/.zephyr.subs.  If the file can not be opened in this case
907 * only, no error message is printed.
908 */
909void owl_function_loadsubs(char *file)
910{
911  int ret, ret2;
912  char *foo;
913
914  if (file==NULL) {
915    ret=owl_zephyr_loadsubs(NULL, 0);
916  } else {
917    ret=owl_zephyr_loadsubs(file, 1);
918  }
919
920  /* for backwards compatibility for now */
921  ret2=owl_zephyr_loaddefaultsubs();
922
923  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
924
925  foo=file?file:"file";
926  if (ret==0 && ret2==0) {
927    if (!file) {
928      owl_function_makemsg("Subscribed to messages.");
929    } else {
930      owl_function_makemsg("Subscribed to messages from %s", file);
931    }
932  } else if (ret==-1) {
933    owl_function_error("Could not read %s", foo);
934  } else {
935    owl_function_error("Error subscribing to messages");
936  }
937}
938
939void owl_function_loadloginsubs(char *file)
940{
941  int ret;
942
943  ret=owl_zephyr_loadloginsubs(file);
944
945  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
946  if (ret==0) {
947    owl_function_makemsg("Subscribed to login messages from file.");
948  } else if (ret==-1) {
949    owl_function_error("Could not open file for login subscriptions.");
950  } else {
951    owl_function_error("Error subscribing to login messages from file.");
952  }
953}
954
955void owl_callback_aimlogin(owl_editwin *e) {
956  owl_function_aimlogin(owl_editwin_get_command(e),
957                        owl_editwin_get_text(e));
958}
959
960void owl_function_aimlogin(char *user, char *passwd) {
961  int ret;
962
963  /* clear the buddylist */
964  owl_buddylist_clear(owl_global_get_buddylist(&g));
965
966  /* try to login */
967  ret=owl_aim_login(user, passwd);
968  if (ret) owl_function_makemsg("Warning: login for %s failed.\n", user);
969}
970
971void owl_function_suspend()
972{
973  endwin();
974  printf("\n");
975  kill(getpid(), SIGSTOP);
976
977  /* resize to reinitialize all the windows when we come back */
978  owl_command_resize();
979}
980
981void owl_function_zaway_toggle()
982{
983  if (!owl_global_is_zaway(&g)) {
984    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
985    owl_function_zaway_on();
986  } else {
987    owl_function_zaway_off();
988  }
989}
990
991void owl_function_zaway_on()
992{
993  owl_global_set_zaway_on(&g);
994  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
995}
996
997void owl_function_zaway_off()
998{
999  owl_global_set_zaway_off(&g);
1000  owl_function_makemsg("zaway off");
1001}
1002
1003void owl_function_aaway_toggle()
1004{
1005  if (!owl_global_is_aaway(&g)) {
1006    owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
1007    owl_function_aaway_on();
1008  } else {
1009    owl_function_aaway_off();
1010  }
1011}
1012
1013void owl_function_aaway_on()
1014{
1015  owl_global_set_aaway_on(&g);
1016  /* owl_aim_set_awaymsg(owl_global_get_zaway_msg(&g)); */
1017  owl_function_makemsg("AIM away set (%s)", owl_global_get_aaway_msg(&g));
1018}
1019
1020void owl_function_aaway_off()
1021{
1022  owl_global_set_aaway_off(&g);
1023  /* owl_aim_set_awaymsg(""); */
1024  owl_function_makemsg("AIM away off");
1025}
1026
1027void owl_function_quit()
1028{
1029  char *ret;
1030 
1031  /* zlog out if we need to */
1032  if (owl_global_is_shutdownlogout(&g)) {
1033    owl_zephyr_zlog_out();
1034  }
1035
1036  /* execute the commands in shutdown */
1037  ret = owl_perlconfig_execute("BarnOwl::Hooks::_shutdown();");
1038  if (ret) owl_free(ret);
1039
1040  /* signal our child process, if any */
1041  if (owl_global_get_newmsgproc_pid(&g)) {
1042    kill(owl_global_get_newmsgproc_pid(&g), SIGHUP);
1043  }
1044
1045  /* Quit zephyr */
1046  owl_zephyr_shutdown();
1047 
1048  /* Quit AIM */
1049  if (owl_global_is_aimloggedin(&g)) {
1050    owl_aim_logout();
1051  }
1052
1053  /* done with curses */
1054  endwin();
1055
1056  /* restore terminal settings */
1057  tcsetattr(0, TCSAFLUSH, owl_global_get_startup_tio(&g));
1058
1059  owl_function_debugmsg("Quitting Owl");
1060  exit(0);
1061}
1062
1063void owl_function_openurl()
1064{
1065  /* visit the first url in the current message */
1066  owl_message *m;
1067  owl_view *v;
1068  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
1069  int webbrowser;
1070
1071  webbrowser = owl_global_get_webbrowser(&g);
1072
1073  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
1074    owl_function_error("No browser selected");
1075    return;
1076  }
1077
1078  v=owl_global_get_current_view(&g);
1079 
1080  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1081
1082  if (!m || owl_view_get_size(v)==0) {
1083    owl_function_error("No current message selected");
1084    return;
1085  }
1086
1087  text=owl_message_get_text(m);
1088
1089  /* First look for a good URL */ 
1090  if ((ptr1=strstr(text, "http://"))!=NULL) {
1091    ptr2=strpbrk(ptr1, " \n\t");
1092    if (ptr2) {
1093      strncpy(url, ptr1, ptr2-ptr1+1);
1094      url[ptr2-ptr1+1]='\0';
1095    } else {
1096      strcpy(url, ptr1);
1097    }
1098
1099    /* if we had <http strip a trailing > */
1100    if (ptr1>text && ptr1[-1]=='<') {
1101      if (url[strlen(url)-1]=='>') {
1102        url[strlen(url)-1]='\0';
1103      }
1104    }
1105  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
1106    /* Look for an https URL */ 
1107    ptr2=strpbrk(ptr1, " \n\t");
1108    if (ptr2) {
1109      strncpy(url, ptr1, ptr2-ptr1+1);
1110      url[ptr2-ptr1+1]='\0';
1111    } else {
1112      strcpy(url, ptr1);
1113    }
1114   
1115    /* if we had <http strip a trailing > */
1116    if (ptr1>text && ptr1[-1]=='<') {
1117      if (url[strlen(url)-1]=='>') {
1118        url[strlen(url)-1]='\0';
1119      }
1120    }
1121  } else if ((ptr1=strstr(text, "www."))!=NULL) {
1122    /* if we can't find a real url look for www.something */
1123    ptr2=strpbrk(ptr1, " \n\t");
1124    if (ptr2) {
1125      strncpy(url, ptr1, ptr2-ptr1+1);
1126      url[ptr2-ptr1+1]='\0';
1127    } else {
1128      strcpy(url, ptr1);
1129    }
1130  } else {
1131    owl_function_beep();
1132    owl_function_error("Could not find URL to open.");
1133    return;
1134  }
1135
1136  /* Make sure there aren't any quotes or \'s in the url */
1137  for (ptr1 = url; *ptr1; ptr1++) {
1138    if (*ptr1 == '"' || *ptr1 == '\\') {
1139      owl_function_beep();
1140      owl_function_error("URL contains invalid characters.");
1141      return;
1142    }
1143  }
1144 
1145  /* NOTE: There are potentially serious security issues here... */
1146
1147  /* open the page */
1148  owl_function_makemsg("Opening %s", url);
1149  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
1150    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
1151    system(tmpbuff); 
1152  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
1153    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
1154    system(tmpbuff); 
1155  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
1156    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
1157    system(tmpbuff); 
1158  }
1159}
1160
1161void owl_function_calculate_topmsg(int direction)
1162{
1163  int recwinlines, topmsg, curmsg;
1164  owl_view *v;
1165
1166  v=owl_global_get_current_view(&g);
1167  curmsg=owl_global_get_curmsg(&g);
1168  topmsg=owl_global_get_topmsg(&g);
1169  recwinlines=owl_global_get_recwin_lines(&g);
1170
1171  /*
1172  if (owl_view_get_size(v) < 1) {
1173    return;
1174  }
1175  */
1176
1177  switch (owl_global_get_scrollmode(&g)) {
1178  case OWL_SCROLLMODE_TOP:
1179    topmsg = owl_function_calculate_topmsg_top(direction, v, curmsg, topmsg, recwinlines);
1180    break;
1181  case OWL_SCROLLMODE_NEARTOP:
1182    topmsg = owl_function_calculate_topmsg_neartop(direction, v, curmsg, topmsg, recwinlines);
1183    break;
1184  case OWL_SCROLLMODE_CENTER:
1185    topmsg = owl_function_calculate_topmsg_center(direction, v, curmsg, topmsg, recwinlines);
1186    break;
1187  case OWL_SCROLLMODE_PAGED:
1188    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 0);
1189    break;
1190  case OWL_SCROLLMODE_PAGEDCENTER:
1191    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 1);
1192    break;
1193  case OWL_SCROLLMODE_NORMAL:
1194  default:
1195    topmsg = owl_function_calculate_topmsg_normal(direction, v, curmsg, topmsg, recwinlines);
1196  }
1197  owl_function_debugmsg("Calculated a topmsg of %i", topmsg);
1198  owl_global_set_topmsg(&g, topmsg);
1199}
1200
1201/* Returns what the new topmsg should be. 
1202 * Passed the last direction of movement,
1203 * the current view,
1204 * the current message number in the view,
1205 * the top message currently being displayed,
1206 * and the number of lines in the recwin.
1207 */
1208int owl_function_calculate_topmsg_top(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1209{
1210  return(curmsg);
1211}
1212
1213int owl_function_calculate_topmsg_neartop(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1214{
1215  if (curmsg>0 
1216      && (owl_message_get_numlines(owl_view_get_element(v, curmsg-1))
1217          <  recwinlines/2)) {
1218    return(curmsg-1);
1219  } else {
1220    return(curmsg);
1221  }
1222}
1223 
1224int owl_function_calculate_topmsg_center(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1225{
1226  int i, last, lines;
1227
1228  last = curmsg;
1229  lines = 0;
1230  for (i=curmsg-1; i>=0; i--) {
1231    lines += owl_message_get_numlines(owl_view_get_element(v, i));
1232    if (lines > recwinlines/2) break;
1233    last = i;
1234  }
1235  return(last);
1236}
1237 
1238int owl_function_calculate_topmsg_paged(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines, int center_on_page)
1239{
1240  int i, last, lines, savey;
1241 
1242  /* If we're off the top of the screen, scroll up such that the
1243   * curmsg is near the botton of the screen. */
1244  if (curmsg < topmsg) {
1245    last = curmsg;
1246    lines = 0;
1247    for (i=curmsg; i>=0; i--) {
1248      lines += owl_message_get_numlines(owl_view_get_element(v, i));
1249      if (lines > recwinlines) break;
1250    last = i;
1251    }
1252    if (center_on_page) {
1253      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1254    } else {
1255      return(last);
1256    }
1257  }
1258
1259  /* Find number of lines from top to bottom of curmsg (store in savey) */
1260  savey=0;
1261  for (i=topmsg; i<=curmsg; i++) {
1262    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1263  }
1264
1265  /* if we're off the bottom of the screen, scroll down */
1266  if (savey > recwinlines) {
1267    if (center_on_page) {
1268      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1269    } else {
1270      return(curmsg);
1271    }
1272  }
1273
1274  /* else just stay as we are... */
1275  return(topmsg);
1276}
1277
1278int owl_function_calculate_topmsg_normal(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1279{
1280  int savey, i, foo, y;
1281
1282  if (curmsg<0) return(topmsg);
1283   
1284  /* If we're off the top of the screen then center */
1285  if (curmsg<topmsg) {
1286    topmsg=owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
1287  }
1288
1289  /* If curmsg is so far past topmsg that there are more messages than
1290     lines, skip the line counting that follows because we're
1291     certainly off screen.  */
1292  savey=curmsg-topmsg;
1293  if (savey <= recwinlines) {
1294    /* Find number of lines from top to bottom of curmsg (store in savey) */
1295    savey = 0;
1296    for (i=topmsg; i<=curmsg; i++) {
1297      savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1298    }
1299  }
1300
1301  /* If we're off the bottom of the screen, set the topmsg to curmsg
1302   * and scroll upwards */
1303  if (savey > recwinlines) {
1304    topmsg=curmsg;
1305    savey=owl_message_get_numlines(owl_view_get_element(v, curmsg));
1306    direction=OWL_DIRECTION_UPWARDS;
1307  }
1308 
1309  /* If our bottom line is less than 1/4 down the screen then scroll up */
1310  if (direction == OWL_DIRECTION_UPWARDS || direction == OWL_DIRECTION_NONE) {
1311    if (savey < (recwinlines / 4)) {
1312      y=0;
1313      for (i=curmsg; i>=0; i--) {
1314        foo=owl_message_get_numlines(owl_view_get_element(v, i));
1315        /* will we run the curmsg off the screen? */
1316        if ((foo+y) >= recwinlines) {
1317          i++;
1318          if (i>curmsg) i=curmsg;
1319          break;
1320        }
1321        /* have saved 1/2 the screen space? */
1322        y+=foo;
1323        if (y > (recwinlines / 2)) break;
1324      }
1325      if (i<0) i=0;
1326      return(i);
1327    }
1328  }
1329
1330  if (direction == OWL_DIRECTION_DOWNWARDS || direction == OWL_DIRECTION_NONE) {
1331    /* If curmsg bottom line is more than 3/4 down the screen then scroll down */
1332    if (savey > ((recwinlines * 3)/4)) {
1333      y=0;
1334      /* count lines from the top until we can save 1/2 the screen size */
1335      for (i=topmsg; i<curmsg; i++) {
1336        y+=owl_message_get_numlines(owl_view_get_element(v, i));
1337        if (y > (recwinlines / 2)) break;
1338      }
1339      if (i==curmsg) {
1340        i--;
1341      }
1342      return(i+1);
1343    }
1344  }
1345
1346  return(topmsg);
1347}
1348
1349void owl_function_resize()
1350{
1351  owl_global_set_resize_pending(&g);
1352}
1353
1354void owl_function_run_buffercommand()
1355{
1356  owl_editwin_do_callback(owl_global_get_typwin(&g));
1357}
1358
1359void owl_function_debugmsg(char *fmt, ...)
1360{
1361  FILE *file;
1362  time_t now;
1363  char buff1[LINE], buff2[LINE];
1364  va_list ap;
1365  va_start(ap, fmt);
1366
1367  if (!owl_global_is_debug_fast(&g)) return;
1368
1369  file=fopen(owl_global_get_debug_file(&g), "a");
1370  if (!file) return;
1371
1372  now=time(NULL);
1373  strcpy(buff1, ctime(&now));
1374  buff1[strlen(buff1)-1]='\0';
1375
1376  owl_global_get_runtime_string(&g, buff2);
1377 
1378  fprintf(file, "[%i -  %s - %s]: ", (int) getpid(), buff1, buff2);
1379  vfprintf(file, fmt, ap);
1380  fprintf(file, "\n");
1381  fclose(file);
1382
1383  va_end(ap);
1384}
1385
1386void owl_function_refresh()
1387{
1388  owl_function_resize();
1389}
1390
1391void owl_function_beep()
1392{
1393  if (owl_global_is_bell(&g)) {
1394    beep();
1395    owl_global_set_needrefresh(&g); /* do we really need this? */
1396  }
1397}
1398
1399void owl_function_subscribe(char *class, char *inst, char *recip)
1400{
1401  int ret;
1402
1403  ret=owl_zephyr_sub(class, inst, recip);
1404  if (ret) {
1405    owl_function_error("Error subscribing.");
1406  } else {
1407    owl_function_makemsg("Subscribed.");
1408  }
1409}
1410
1411void owl_function_unsubscribe(char *class, char *inst, char *recip)
1412{
1413  int ret;
1414
1415  ret=owl_zephyr_unsub(class, inst, recip);
1416  if (ret) {
1417    owl_function_error("Error subscribing.");
1418  } else {
1419    owl_function_makemsg("Unsubscribed.");
1420  }
1421}
1422
1423void owl_function_set_cursor(WINDOW *win)
1424{
1425  wnoutrefresh(win);
1426}
1427
1428void owl_function_full_redisplay()
1429{
1430  redrawwin(owl_global_get_curs_recwin(&g));
1431  redrawwin(owl_global_get_curs_sepwin(&g));
1432  // Work around curses segfualts with windows off the screen
1433  if (g.lines >= owl_global_get_typwin_lines(&g)+2)
1434      redrawwin(owl_global_get_curs_typwin(&g));
1435  if (g.lines >= 2)
1436      redrawwin(owl_global_get_curs_msgwin(&g));
1437
1438  wnoutrefresh(owl_global_get_curs_recwin(&g));
1439  wnoutrefresh(owl_global_get_curs_sepwin(&g));
1440  wnoutrefresh(owl_global_get_curs_typwin(&g));
1441  wnoutrefresh(owl_global_get_curs_msgwin(&g));
1442 
1443  sepbar("");
1444  owl_function_makemsg("");
1445
1446  owl_global_set_needrefresh(&g);
1447}
1448
1449void owl_function_popless_text(char *text)
1450{
1451  owl_popwin *pw;
1452  owl_viewwin *v;
1453
1454  pw=owl_global_get_popwin(&g);
1455  v=owl_global_get_viewwin(&g);
1456
1457  owl_popwin_up(pw);
1458  owl_viewwin_init_text(v, owl_popwin_get_curswin(pw),
1459                        owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1460                        text);
1461  owl_popwin_refresh(pw);
1462  owl_viewwin_redisplay(v, 0);
1463  owl_global_set_needrefresh(&g);
1464}
1465
1466void owl_function_popless_fmtext(owl_fmtext *fm)
1467{
1468  owl_popwin *pw;
1469  owl_viewwin *v;
1470
1471  pw=owl_global_get_popwin(&g);
1472  v=owl_global_get_viewwin(&g);
1473
1474  owl_popwin_up(pw);
1475  owl_viewwin_init_fmtext(v, owl_popwin_get_curswin(pw),
1476                   owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1477                   fm);
1478  owl_popwin_refresh(pw);
1479  owl_viewwin_redisplay(v, 0);
1480  owl_global_set_needrefresh(&g);
1481}
1482
1483void owl_function_popless_file(char *filename)
1484{
1485  owl_fmtext fm;
1486  FILE *file;
1487  char buff[1024];
1488
1489  file=fopen(filename, "r");
1490  if (!file) {
1491    owl_function_error("Could not open file: %s", filename);
1492    return;
1493  }
1494
1495  owl_fmtext_init_null(&fm);
1496  while (fgets(buff, 1024, file)) {
1497    owl_fmtext_append_normal(&fm, buff);
1498    /*    owl_fmtext_append_normal(&fm, "\n"); */
1499  }
1500
1501  owl_function_popless_fmtext(&fm);
1502  owl_fmtext_free(&fm);
1503  fclose(file);
1504}
1505
1506void owl_function_about()
1507{
1508  char buff[5000];
1509
1510  sprintf(buff, "This is owl version %s\n", OWL_VERSION_STRING);
1511  strcat(buff, "\nOwl was written by James Kretchmar at the Massachusetts\n");
1512  strcat(buff, "Institute of Technology.  The first version, 0.5, was\n");
1513  strcat(buff, "released in March 2002.\n");
1514  strcat(buff, "\n");
1515  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
1516  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
1517  strcat(buff, "between Witches and Wizards.\n");
1518  strcat(buff, "\n");
1519  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
1520  strcat(buff, "\n");
1521  strcat(buff, "Permission to use, copy, modify, and distribute this\n");
1522  strcat(buff, "software and its documentation for any purpose and without\n");
1523  strcat(buff, "fee is hereby granted, provided that the above copyright\n");
1524  strcat(buff, "notice and this permission notice appear in all copies\n");
1525  strcat(buff, "and in supporting documentation.  No representation is\n");
1526  strcat(buff, "made about the suitability of this software for any\n");
1527  strcat(buff, "purpose.  It is provided \"as is\" without express\n");
1528  strcat(buff, "or implied warranty.\n");
1529  owl_function_popless_text(buff);
1530}
1531
1532void owl_function_info()
1533{
1534  owl_message *m;
1535  owl_fmtext fm, attrfm;
1536  char buff[10000];
1537  owl_view *v;
1538#ifdef HAVE_LIBZEPHYR
1539  ZNotice_t *n;
1540#endif
1541
1542  owl_fmtext_init_null(&fm);
1543 
1544  v=owl_global_get_current_view(&g);
1545  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1546  if (!m || owl_view_get_size(v)==0) {
1547    owl_function_error("No message selected\n");
1548    return;
1549  }
1550
1551  owl_fmtext_append_bold(&fm, "General Information:\n");
1552  owl_fmtext_append_normal(&fm, "  Msg Id    : ");
1553  sprintf(buff, "%i", owl_message_get_id(m));
1554  owl_fmtext_append_normal(&fm, buff);
1555  owl_fmtext_append_normal(&fm, "\n");
1556
1557  owl_fmtext_append_normal(&fm, "  Type      : ");
1558  owl_fmtext_append_bold(&fm, owl_message_get_type(m));
1559  owl_fmtext_append_normal(&fm, "\n");
1560
1561  if (owl_message_is_direction_in(m)) {
1562    owl_fmtext_append_normal(&fm, "  Direction : in\n");
1563  } else if (owl_message_is_direction_out(m)) {
1564    owl_fmtext_append_normal(&fm, "  Direction : out\n");
1565  } else if (owl_message_is_direction_none(m)) {
1566    owl_fmtext_append_normal(&fm, "  Direction : none\n");
1567  } else {
1568    owl_fmtext_append_normal(&fm, "  Direction : unknown\n");
1569  }
1570
1571  owl_fmtext_append_normal(&fm, "  Time      : ");
1572  owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1573  owl_fmtext_append_normal(&fm, "\n");
1574
1575  if (!owl_message_is_type_admin(m)) {
1576    owl_fmtext_append_normal(&fm, "  Sender    : ");
1577    owl_fmtext_append_normal(&fm, owl_message_get_sender(m));
1578    owl_fmtext_append_normal(&fm, "\n");
1579   
1580    owl_fmtext_append_normal(&fm, "  Recipient : ");
1581    owl_fmtext_append_normal(&fm, owl_message_get_recipient(m));
1582    owl_fmtext_append_normal(&fm, "\n");
1583  }
1584   
1585  if (owl_message_is_type_zephyr(m)) {
1586    owl_fmtext_append_bold(&fm, "\nZephyr Specific Information:\n");
1587   
1588    owl_fmtext_append_normal(&fm, "  Class     : ");
1589    owl_fmtext_append_normal(&fm, owl_message_get_class(m));
1590    owl_fmtext_append_normal(&fm, "\n");
1591    owl_fmtext_append_normal(&fm, "  Instance  : ");
1592    owl_fmtext_append_normal(&fm, owl_message_get_instance(m));
1593    owl_fmtext_append_normal(&fm, "\n");
1594    owl_fmtext_append_normal(&fm, "  Opcode    : ");
1595    owl_fmtext_append_normal(&fm, owl_message_get_opcode(m));
1596    owl_fmtext_append_normal(&fm, "\n");
1597   
1598    owl_fmtext_append_normal(&fm, "  Time      : ");
1599    owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1600    owl_fmtext_append_normal(&fm, "\n");
1601#ifdef HAVE_LIBZEPHYR
1602    if (owl_message_is_direction_in(m)) {
1603      char *ptr, tmpbuff[1024];
1604      int i, j, fields, len;
1605
1606      n=owl_message_get_notice(m);
1607
1608      if (!owl_message_is_pseudo(m)) {
1609        owl_fmtext_append_normal(&fm, "  Kind      : ");
1610        if (n->z_kind==UNSAFE) {
1611          owl_fmtext_append_normal(&fm, "UNSAFE\n");
1612        } else if (n->z_kind==UNACKED) {
1613          owl_fmtext_append_normal(&fm, "UNACKED\n");
1614        } else if (n->z_kind==ACKED) {
1615          owl_fmtext_append_normal(&fm, "ACKED\n");
1616        } else if (n->z_kind==HMACK) {
1617          owl_fmtext_append_normal(&fm, "HMACK\n");
1618        } else if (n->z_kind==HMCTL) {
1619          owl_fmtext_append_normal(&fm, "HMCTL\n");
1620        } else if (n->z_kind==SERVACK) {
1621          owl_fmtext_append_normal(&fm, "SERVACK\n");
1622        } else if (n->z_kind==SERVNAK) {
1623          owl_fmtext_append_normal(&fm, "SERVNACK\n");
1624        } else if (n->z_kind==CLIENTACK) {
1625          owl_fmtext_append_normal(&fm, "CLIENTACK\n");
1626        } else if (n->z_kind==STAT) {
1627          owl_fmtext_append_normal(&fm, "STAT\n");
1628        } else {
1629          owl_fmtext_append_normal(&fm, "ILLEGAL VALUE\n");
1630        }
1631      }
1632      owl_fmtext_append_normal(&fm, "  Host      : ");
1633      owl_fmtext_append_normal(&fm, owl_message_get_hostname(m));
1634
1635      if (!owl_message_is_pseudo(m)) {
1636        owl_fmtext_append_normal(&fm, "\n");
1637        sprintf(buff, "  Port      : %i\n", ntohs(n->z_port));
1638        owl_fmtext_append_normal(&fm, buff);
1639
1640        owl_fmtext_append_normal(&fm,    "  Auth      : ");
1641        owl_fmtext_append_normal(&fm, owl_zephyr_get_authstr(n));
1642        owl_fmtext_append_normal(&fm, "\n");
1643       
1644        /* fix this */
1645        sprintf(buff, "  Checkd Ath: %i\n", n->z_checked_auth);
1646        sprintf(buff, "%s  Multi notc: %s\n", buff, n->z_multinotice);
1647        sprintf(buff, "%s  Num other : %i\n", buff, n->z_num_other_fields);
1648        sprintf(buff, "%s  Msg Len   : %i\n", buff, n->z_message_len);
1649        owl_fmtext_append_normal(&fm, buff);
1650       
1651        sprintf(buff, "  Fields    : %i\n", owl_zephyr_get_num_fields(n));
1652        owl_fmtext_append_normal(&fm, buff);
1653       
1654        fields=owl_zephyr_get_num_fields(n);
1655        for (i=0; i<fields; i++) {
1656          sprintf(buff, "  Field %i   : ", i+1);
1657         
1658          ptr=owl_zephyr_get_field(n, i+1);
1659          len=strlen(ptr);
1660          if (len<30) {
1661            strncpy(tmpbuff, ptr, len);
1662            tmpbuff[len]='\0';
1663          } else {
1664            strncpy(tmpbuff, ptr, 30);
1665            tmpbuff[30]='\0';
1666            strcat(tmpbuff, "...");
1667          }
1668          owl_free(ptr);
1669         
1670          for (j=0; j<strlen(tmpbuff); j++) {
1671            if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1672            if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1673          }
1674         
1675          strcat(buff, tmpbuff);
1676          strcat(buff, "\n");
1677          owl_fmtext_append_normal(&fm, buff);
1678        }
1679        owl_fmtext_append_normal(&fm, "  Default Fm:");
1680        owl_fmtext_append_normal(&fm, n->z_default_format);
1681      }
1682     
1683    }
1684#endif   
1685  }
1686
1687  if (owl_message_is_type_aim(m)) {
1688    owl_fmtext_append_bold(&fm, "\nAIM Specific Information:\n");
1689  }
1690
1691  owl_fmtext_append_bold(&fm, "\nOwl Message Attributes:\n");
1692  owl_message_attributes_tofmtext(m, &attrfm);
1693  owl_fmtext_append_fmtext(&fm, &attrfm);
1694 
1695  owl_function_popless_fmtext(&fm);
1696  owl_fmtext_free(&fm);
1697  owl_fmtext_free(&attrfm);
1698}
1699
1700/* print the current message in a popup window.
1701 * Use the 'default' style regardless of whatever
1702 * style the user may be using
1703 */
1704void owl_function_curmsg_to_popwin()
1705{
1706  owl_popwin *pw;
1707  owl_view *v;
1708  owl_message *m;
1709  owl_style *s;
1710  owl_fmtext fm;
1711
1712  v=owl_global_get_current_view(&g);
1713  s=owl_global_get_style_by_name(&g, "default");
1714  pw=owl_global_get_popwin(&g);
1715
1716  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1717
1718  if (!m || owl_view_get_size(v)==0) {
1719    owl_function_error("No current message");
1720    return;
1721  }
1722
1723  owl_fmtext_init_null(&fm);
1724  owl_style_get_formattext(s, &fm, m);
1725
1726  owl_function_popless_fmtext(&fm);
1727  owl_fmtext_free(&fm);
1728}
1729
1730void owl_function_page_curmsg(int step)
1731{
1732  /* scroll down or up within the current message IF the message is truncated */
1733
1734  int offset, curmsg, lines;
1735  owl_view *v;
1736  owl_message *m;
1737
1738  offset=owl_global_get_curmsg_vert_offset(&g);
1739  v=owl_global_get_current_view(&g);
1740  curmsg=owl_global_get_curmsg(&g);
1741  m=owl_view_get_element(v, curmsg);
1742  if (!m || owl_view_get_size(v)==0) return;
1743  lines=owl_message_get_numlines(m);
1744
1745  if (offset==0) {
1746    /* Bail if the curmsg isn't the last one displayed */
1747    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
1748      owl_function_makemsg("The entire message is already displayed");
1749      return;
1750    }
1751   
1752    /* Bail if we're not truncated */
1753    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
1754      owl_function_makemsg("The entire message is already displayed");
1755      return;
1756    }
1757  }
1758 
1759 
1760  /* don't scroll past the last line */
1761  if (step>0) {
1762    if (offset+step > lines-1) {
1763      owl_global_set_curmsg_vert_offset(&g, lines-1);
1764    } else {
1765      owl_global_set_curmsg_vert_offset(&g, offset+step);
1766    }
1767  }
1768
1769  /* would we be before the beginning of the message? */
1770  if (step<0) {
1771    if (offset+step<0) {
1772      owl_global_set_curmsg_vert_offset(&g, 0);
1773    } else {
1774      owl_global_set_curmsg_vert_offset(&g, offset+step);
1775    }
1776  }
1777 
1778  /* redisplay */
1779  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1780  owl_global_set_needrefresh(&g);
1781}
1782
1783void owl_function_resize_typwin(int newsize)
1784{
1785  owl_global_set_typwin_lines(&g, newsize);
1786  owl_function_resize();
1787}
1788
1789void owl_function_typwin_grow()
1790{
1791  int i;
1792
1793  i=owl_global_get_typwin_lines(&g);
1794  owl_function_resize_typwin(i+1);
1795}
1796
1797void owl_function_typwin_shrink()
1798{
1799  int i;
1800
1801  i=owl_global_get_typwin_lines(&g);
1802  if (i>2) {
1803    owl_function_resize_typwin(i-1);
1804  }
1805}
1806
1807void owl_function_mainwin_pagedown()
1808{
1809  int i;
1810
1811  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1812  if (i<0) return;
1813  if (owl_mainwin_is_last_msg_truncated(owl_global_get_mainwin(&g))
1814      && (owl_global_get_curmsg(&g) < i)
1815      && (i>0)) {
1816    i--;
1817  }
1818  owl_global_set_curmsg(&g, i);
1819  owl_function_nextmsg();
1820}
1821
1822void owl_function_mainwin_pageup()
1823{
1824  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1825  owl_function_prevmsg();
1826}
1827
1828void owl_function_getsubs()
1829{
1830  char *buff;
1831
1832  buff=owl_zephyr_getsubs();
1833
1834  if (buff) {
1835    owl_function_popless_text(buff);
1836  } else {
1837    owl_function_popless_text("Error getting subscriptions");
1838  }
1839           
1840  owl_free(buff);
1841}
1842
1843#define PABUFLEN 5000
1844void owl_function_printallvars()
1845{
1846  char buff[PABUFLEN], *pos, *name;
1847  owl_list varnames;
1848  int i, numvarnames, rem;
1849
1850  pos = buff;
1851  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1852  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1853  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1854  rem = (buff+PABUFLEN)-pos-1;
1855  numvarnames = owl_list_get_size(&varnames);
1856  for (i=0; i<numvarnames; i++) {
1857    name = owl_list_get_element(&varnames, i);
1858    if (name && name[0]!='_') {
1859      rem = (buff+PABUFLEN)-pos-1;   
1860      pos += snprintf(pos, rem, "\n%-20s = ", name);
1861      rem = (buff+PABUFLEN)-pos-1;   
1862      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1863      pos = buff+strlen(buff);
1864    }
1865  }
1866  rem = (buff+PABUFLEN)-pos-1;   
1867  snprintf(pos, rem, "\n");
1868  owl_variable_dict_namelist_free(&varnames);
1869 
1870  owl_function_popless_text(buff);
1871}
1872
1873void owl_function_show_variables()
1874{
1875  owl_list varnames;
1876  owl_fmtext fm; 
1877  int i, numvarnames;
1878  char *varname;
1879
1880  owl_fmtext_init_null(&fm);
1881  owl_fmtext_append_bold(&fm, 
1882      "Variables: (use 'show variable <name>' for details)\n");
1883  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1884  numvarnames = owl_list_get_size(&varnames);
1885  for (i=0; i<numvarnames; i++) {
1886    varname = owl_list_get_element(&varnames, i);
1887    if (varname && varname[0]!='_') {
1888      owl_variable_describe(owl_global_get_vardict(&g), varname, &fm);
1889    }
1890  }
1891  owl_variable_dict_namelist_free(&varnames);
1892  owl_function_popless_fmtext(&fm);
1893  owl_fmtext_free(&fm);
1894}
1895
1896void owl_function_show_variable(char *name)
1897{
1898  owl_fmtext fm; 
1899
1900  owl_fmtext_init_null(&fm);
1901  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1902  owl_function_popless_fmtext(&fm);
1903  owl_fmtext_free(&fm); 
1904}
1905
1906/* note: this applies to global message list, not to view.
1907 * If flag is 1, deletes.  If flag is 0, undeletes. */
1908void owl_function_delete_by_id(int id, int flag)
1909{
1910  owl_messagelist *ml;
1911  owl_message *m;
1912  ml = owl_global_get_msglist(&g);
1913  m = owl_messagelist_get_by_id(ml, id);
1914  if (m) {
1915    if (flag == 1) {
1916      owl_message_mark_delete(m);
1917    } else if (flag == 0) {
1918      owl_message_unmark_delete(m);
1919    }
1920    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1921    owl_global_set_needrefresh(&g);
1922  } else {
1923    owl_function_error("No message with id %d: unable to mark for (un)delete",id);
1924  }
1925}
1926
1927void owl_function_delete_automsgs()
1928{
1929  /* mark for deletion all messages in the current view that match the
1930   * 'trash' filter */
1931
1932  int i, j, count;
1933  owl_message *m;
1934  owl_view *v;
1935  owl_filter *f;
1936
1937  /* get the trash filter */
1938  f=owl_global_get_filter(&g, "trash");
1939  if (!f) {
1940    owl_function_error("No trash filter defined");
1941    return;
1942  }
1943
1944  v=owl_global_get_current_view(&g);
1945
1946  count=0;
1947  j=owl_view_get_size(v);
1948  for (i=0; i<j; i++) {
1949    m=owl_view_get_element(v, i);
1950    if (owl_filter_message_match(f, m)) {
1951      count++;
1952      owl_message_mark_delete(m);
1953    }
1954  }
1955  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1956  owl_function_makemsg("%i messages marked for deletion", count);
1957  owl_global_set_needrefresh(&g);
1958}
1959
1960void owl_function_status()
1961{
1962  char buff[5000];
1963  time_t start;
1964  int up, days, hours, minutes;
1965  owl_fmtext fm;
1966
1967  owl_fmtext_init_null(&fm);
1968
1969  start=owl_global_get_starttime(&g);
1970
1971  owl_fmtext_append_normal(&fm, "General Information:\n");
1972
1973  owl_fmtext_append_normal(&fm, "  Version: ");
1974  owl_fmtext_append_normal(&fm, OWL_VERSION_STRING);
1975  owl_fmtext_append_normal(&fm, "\n");
1976
1977  owl_fmtext_append_normal(&fm, "  Startup Arugments: ");
1978  owl_fmtext_append_normal(&fm, owl_global_get_startupargs(&g));
1979  owl_fmtext_append_normal(&fm, "\n");
1980
1981  owl_fmtext_append_normal(&fm, "  Current Directory: ");
1982  (void) getcwd(buff, MAXPATHLEN);
1983  owl_fmtext_append_normal(&fm, buff);
1984  owl_fmtext_append_normal(&fm, "\n");
1985
1986  sprintf(buff, "  Startup Time: %s", ctime(&start));
1987  owl_fmtext_append_normal(&fm, buff);
1988
1989  up=owl_global_get_runtime(&g);
1990  days=up/86400;
1991  up-=days*86400;
1992  hours=up/3600;
1993  up-=hours*3600;
1994  minutes=up/60;
1995  up-=minutes*60;
1996  sprintf(buff, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
1997  owl_fmtext_append_normal(&fm, buff);
1998
1999  owl_fmtext_append_normal(&fm, "\nProtocol Options:\n");
2000  owl_fmtext_append_normal(&fm, "  Zephyr included    : ");
2001  if (owl_global_is_havezephyr(&g)) {
2002    owl_fmtext_append_normal(&fm, "yes\n");
2003  } else {
2004    owl_fmtext_append_normal(&fm, "no\n");
2005  }
2006  owl_fmtext_append_normal(&fm, "  AIM included       : yes\n");
2007  owl_fmtext_append_normal(&fm, "  Loopback included  : yes\n");
2008
2009
2010  owl_fmtext_append_normal(&fm, "\nBuild Options:\n");
2011  owl_fmtext_append_normal(&fm, "  Stderr redirection : ");
2012#if OWL_STDERR_REDIR
2013  owl_fmtext_append_normal(&fm, "yes\n");
2014#else
2015  owl_fmtext_append_normal(&fm, "no\n");
2016#endif
2017 
2018
2019  owl_fmtext_append_normal(&fm, "\nMemory Usage:\n");
2020  owl_fmtext_append_normal(&fm, "  Not currently available.\n");
2021  /*
2022  sprintf(buff, "%sMemory Malloced: %i\n", buff, owl_global_get_malloced(&g));
2023  sprintf(buff, "%sMemory Freed: %i\n", buff, owl_global_get_freed(&g));
2024  sprintf(buff, "%sMemory In Use: %i\n", buff, owl_global_get_meminuse(&g));
2025  */
2026
2027  owl_fmtext_append_normal(&fm, "\nAIM Status:\n");
2028  owl_fmtext_append_normal(&fm, "  Logged in: ");
2029  if (owl_global_is_aimloggedin(&g)) {
2030    owl_fmtext_append_normal(&fm, owl_global_get_aim_screenname(&g));
2031    owl_fmtext_append_normal(&fm, "\n");
2032  } else {
2033    owl_fmtext_append_normal(&fm, "(not logged in)\n");
2034  }
2035
2036  owl_fmtext_append_normal(&fm, "  Processing events: ");
2037  if (owl_global_is_doaimevents(&g)) {
2038    owl_fmtext_append_normal(&fm, "yes\n");
2039  } else {
2040    owl_fmtext_append_normal(&fm, "no\n");
2041  }
2042
2043  owl_function_popless_fmtext(&fm);
2044  owl_fmtext_free(&fm);
2045}
2046
2047void owl_function_show_term()
2048{
2049  owl_fmtext fm;
2050  char buff[LINE];
2051
2052  owl_fmtext_init_null(&fm);
2053  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
2054          owl_global_get_lines(&g),
2055          owl_global_get_cols(&g));
2056  owl_fmtext_append_normal(&fm, buff);
2057
2058  if (owl_global_get_hascolors(&g)) {
2059    owl_fmtext_append_normal(&fm, "Color: Yes\n");
2060    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
2061    owl_fmtext_append_normal(&fm, buff);
2062    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
2063    owl_fmtext_append_normal(&fm, buff);
2064  } else {
2065    owl_fmtext_append_normal(&fm, "Color: No\n");
2066  }
2067
2068  owl_function_popless_fmtext(&fm);
2069  owl_fmtext_free(&fm);
2070}
2071
2072/* if type = 0 then normal reply.
2073 * if type = 1 then it's a reply to sender
2074 * if enter = 0 then allow the command to be edited
2075 * if enter = 1 then don't wait for editing
2076 */
2077void owl_function_reply(int type, int enter)
2078{
2079  char *buff=NULL, *oldbuff;
2080  owl_message *m;
2081  owl_filter *f;
2082 
2083  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
2084    owl_function_error("No message selected");
2085  } else {
2086    char *class, *inst, *to, *cc=NULL;
2087   
2088    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
2089    if (!m) {
2090      owl_function_error("No message selected");
2091      return;
2092    }
2093
2094    /* first check if we catch the reply-lockout filter */
2095    f=owl_global_get_filter(&g, "reply-lockout");
2096    if (f) {
2097      if (owl_filter_message_match(f, m)) {
2098        owl_function_error("Sorry, replies to this message have been disabled by the reply-lockout filter");
2099        return;
2100      }
2101    }
2102
2103    /* loopback */
2104    if (owl_message_is_type_loopback(m)) {
2105      owl_function_loopwrite_setup();
2106      return;
2107    }
2108
2109    /* zephyr */
2110    if (owl_message_is_type_zephyr(m)) {
2111      /* if it's a zephyr we sent, send it out the same way again */
2112      if (owl_message_is_direction_out(m)) {
2113        owl_function_zwrite_setup(owl_message_get_zwriteline(m));
2114        owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
2115        return;
2116      }
2117
2118      /* Special case a personal reply to a webzephyr user on a class */
2119      if ((type==1) && !strcasecmp(owl_message_get_opcode(m), OWL_WEBZEPHYR_OPCODE)) {
2120        class=OWL_WEBZEPHYR_CLASS;
2121        inst=owl_message_get_sender(m);
2122        to=OWL_WEBZEPHYR_PRINCIPAL;
2123      } else if (!strcasecmp(owl_message_get_class(m), OWL_WEBZEPHYR_CLASS) && owl_message_is_loginout(m)) {
2124        /* Special case LOGIN/LOGOUT notifications on class "webzephyr" */
2125        class=OWL_WEBZEPHYR_CLASS;
2126        inst=owl_message_get_instance(m);
2127        to=OWL_WEBZEPHYR_PRINCIPAL;
2128      } else if (owl_message_is_loginout(m)) {
2129        /* Normal LOGIN/LOGOUT messages */
2130        class="MESSAGE";
2131        inst="PERSONAL";
2132        to=owl_message_get_sender(m);
2133      } else if (type==1) {
2134        /* Personal reply */
2135        class="MESSAGE";
2136        inst="PERSONAL";
2137        to=owl_message_get_sender(m);
2138      } else {
2139        /* General reply */
2140        class=owl_message_get_class(m);
2141        inst=owl_message_get_instance(m);
2142        to=owl_message_get_recipient(m);
2143        cc=owl_message_get_cc(m);
2144        if (!strcmp(to, "") || !strcmp(to, "*")) {
2145          to="";
2146        } else if (to[0]=='@') {
2147          /* leave it, to get the realm */
2148        } else {
2149          to=owl_message_get_sender(m);
2150        }
2151      }
2152       
2153      /* create the command line */
2154      if (!strcasecmp(owl_message_get_opcode(m), "CRYPT")) {
2155        buff=owl_strdup("zcrypt");
2156      } else {
2157        buff = owl_strdup("zwrite");
2158      }
2159      if (strcasecmp(class, "message")) {
2160        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
2161        owl_free(oldbuff);
2162      }
2163      if (strcasecmp(inst, "personal")) {
2164        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
2165        owl_free(oldbuff);
2166      }
2167      if (*to != '\0') {
2168        char *tmp, *oldtmp, *tmp2;
2169        tmp=short_zuser(to);
2170        if (cc) {
2171          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
2172          owl_free(oldtmp);
2173          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
2174          owl_free(oldbuff);
2175        } else {
2176          if (owl_global_is_smartstrip(&g)) {
2177            tmp2=tmp;
2178            tmp=owl_zephyr_smartstripped_user(tmp2);
2179            owl_free(tmp2);
2180          }
2181          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
2182          owl_free(oldbuff);
2183        }
2184        owl_free(tmp);
2185      }
2186      if (cc) owl_free(cc);
2187    } else if (owl_message_is_type_aim(m)) {
2188      /* aim */
2189      if (owl_message_is_direction_out(m)) {
2190        buff=owl_sprintf("aimwrite %s", owl_message_get_recipient(m));
2191      } else {
2192        buff=owl_sprintf("aimwrite %s", owl_message_get_sender(m));
2193      }
2194    } else {
2195      char *cmd;
2196      if((type==0 && (cmd=owl_message_get_attribute_value(m, "replycmd")))
2197         || (type==1 && (cmd=owl_message_get_attribute_value(m, "replysendercmd")))) {
2198        buff = owl_strdup(cmd);
2199      }
2200    }
2201
2202    if(!buff) {
2203        owl_function_error("I don't know how to reply to that message.");
2204        return;
2205    }
2206   
2207    if (enter) {
2208      owl_history *hist = owl_global_get_cmd_history(&g);
2209      owl_history_store(hist, buff);
2210      owl_history_reset(hist);
2211      owl_function_command_norv(buff);
2212    } else {
2213      owl_function_start_command(buff);
2214    }
2215    owl_free(buff);
2216  }
2217}
2218
2219void owl_function_zlocate(int argc, char **argv, int auth)
2220{
2221  owl_fmtext fm;
2222  char *ptr, buff[LINE];
2223  int i;
2224
2225  owl_fmtext_init_null(&fm);
2226
2227  for (i=0; i<argc; i++) {
2228    ptr=long_zuser(argv[i]);
2229    owl_zephyr_zlocate(ptr, buff, auth);
2230    owl_fmtext_append_normal(&fm, buff);
2231    owl_free(ptr);
2232  }
2233
2234  owl_function_popless_fmtext(&fm);
2235  owl_fmtext_free(&fm);
2236}
2237
2238void owl_function_start_command(char *line)
2239{
2240  int i, j;
2241  owl_editwin *tw;
2242
2243  tw=owl_global_get_typwin(&g);
2244  owl_global_set_typwin_active(&g);
2245  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
2246                        owl_global_get_cmd_history(&g));
2247
2248  owl_editwin_set_locktext(tw, "command: ");
2249  owl_global_set_needrefresh(&g);
2250
2251  j=strlen(line);
2252  for (i=0; i<j; i++) {
2253    owl_editwin_process_char(tw, line[i]);
2254  }
2255  owl_editwin_redisplay(tw, 0);
2256
2257  owl_context_set_editline(owl_global_get_context(&g), tw);
2258  owl_function_activate_keymap("editline");
2259}
2260
2261void owl_function_start_question(char *line)
2262{
2263  owl_editwin *tw;
2264
2265  tw=owl_global_get_typwin(&g);
2266  owl_global_set_typwin_active(&g);
2267  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2268
2269  owl_editwin_set_locktext(tw, line);
2270  owl_global_set_needrefresh(&g);
2271
2272  owl_editwin_redisplay(tw, 0);
2273
2274  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2275  owl_function_activate_keymap("editresponse");
2276}
2277
2278void owl_function_start_password(char *line)
2279{
2280  owl_editwin *tw;
2281
2282  tw=owl_global_get_typwin(&g);
2283  owl_global_set_typwin_active(&g);
2284  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2285  owl_editwin_set_echochar(tw, '*');
2286
2287  owl_editwin_set_locktext(tw, line);
2288  owl_global_set_needrefresh(&g);
2289
2290  owl_editwin_redisplay(tw, 0);
2291
2292  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2293  owl_function_activate_keymap("editresponse");
2294}
2295
2296char *owl_function_exec(int argc, char **argv, char *buff, int type)
2297{
2298  /* if type == 1 display in a popup
2299   * if type == 2 display an admin messages
2300   * if type == 0 return output
2301   * else display in a popup
2302   */
2303  char *newbuff, *redirect = " 2>&1 < /dev/null";
2304  char *out, buff2[1024];
2305  int size;
2306  FILE *p;
2307
2308#if OWL_STDERR_REDIR
2309  redirect = " < /dev/null";
2310#endif
2311
2312  if (argc<2) {
2313    owl_function_error("Wrong number of arguments to the exec command");
2314    return NULL;
2315  }
2316
2317  buff = skiptokens(buff, 1);
2318  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
2319  strcpy(newbuff, buff);
2320  strcat(newbuff, redirect);
2321
2322  if (type == 1) {
2323    owl_popexec_new(newbuff);
2324  } else {
2325    p=popen(newbuff, "r");
2326    out=owl_malloc(1024);
2327    size=1024;
2328    strcpy(out, "");
2329    while (fgets(buff2, 1024, p)!=NULL) {
2330      size+=1024;
2331      out=owl_realloc(out, size);
2332      strcat(out, buff2);
2333    }
2334    pclose(p);
2335   
2336    if (type==1) {
2337      owl_function_popless_text(out);
2338    } else if (type==0) {
2339      return out;
2340    } else if (type==2) {
2341      owl_function_adminmsg(buff, out);
2342    } else {
2343      owl_function_popless_text(out);
2344    }
2345    owl_free(out);
2346  }
2347  return NULL;
2348}
2349
2350char *owl_function_perl(int argc, char **argv, char *buff, int type)
2351{
2352  /* if type == 1 display in a popup
2353   * if type == 2 display an admin messages
2354   * if type == 0 return output
2355   * else display in a popup
2356   */
2357  char *perlout;
2358
2359  if (argc<2) {
2360    owl_function_error("Wrong number of arguments to perl command");
2361    return NULL;
2362  }
2363
2364  /* consume first token (argv[0]) */
2365  buff = skiptokens(buff, 1);
2366
2367  perlout = owl_perlconfig_execute(buff);
2368  if (perlout) { 
2369    if (type==1) {
2370      owl_function_popless_text(perlout);
2371    } else if (type==2) {
2372      owl_function_adminmsg(buff, perlout);
2373    } else if (type==0) {
2374      return perlout;
2375    } else {
2376      owl_function_popless_text(perlout);
2377    }
2378    owl_free(perlout);
2379  }
2380  return NULL;
2381}
2382
2383/* Change the filter associated with the current view.
2384 * This also figures out which message in the new filter
2385 * should have the pointer.
2386 */
2387void owl_function_change_currentview_filter(char *filtname)
2388{
2389  owl_view *v;
2390  owl_filter *f;
2391  int curid=-1, newpos, curmsg;
2392  owl_message *curm=NULL;
2393
2394  v=owl_global_get_current_view(&g);
2395
2396  curmsg=owl_global_get_curmsg(&g);
2397  if (curmsg==-1) {
2398    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2399  } else {
2400    curm=owl_view_get_element(v, curmsg);
2401    if (curm) {
2402      curid=owl_message_get_id(curm);
2403      owl_view_save_curmsgid(v, curid);
2404    }
2405  }
2406
2407  f=owl_global_get_filter(&g, filtname);
2408  if (!f) {
2409    owl_function_error("Unknown filter %s", filtname);
2410    return;
2411  }
2412
2413  owl_view_new_filter(v, f);
2414
2415  /* Figure out what to set the current message to.
2416   * - If the view we're leaving has messages in it, go to the closest message
2417   *   to the last message pointed to in that view.
2418   * - If the view we're leaving is empty, try to restore the position
2419   *   from the last time we were in the new view.  */
2420  if (curm) {
2421    newpos = owl_view_get_nearest_to_msgid(v, curid);
2422  } else {
2423    newpos = owl_view_get_nearest_to_saved(v);
2424  }
2425
2426  owl_global_set_curmsg(&g, newpos);
2427  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2428  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2429  owl_global_set_direction_downwards(&g);
2430}
2431
2432/* Create a new filter, or replace an existing one
2433 * with a new definition.
2434 */
2435void owl_function_create_filter(int argc, char **argv)
2436{
2437  owl_filter *f;
2438  owl_view *v;
2439  int ret, inuse=0;
2440
2441  if (argc < 2) {
2442    owl_function_error("Wrong number of arguments to filter command");
2443    return;
2444  }
2445
2446  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2447
2448  v=owl_global_get_current_view(&g);
2449
2450  /* don't touch the all filter */
2451  if (!strcmp(argv[1], "all")) {
2452    owl_function_error("You may not change the 'all' filter.");
2453    return;
2454  }
2455
2456  /* deal with the case of trying change the filter color */
2457  if (argc==4 && !strcmp(argv[2], "-c")) {
2458    f=owl_global_get_filter(&g, argv[1]);
2459    if (!f) {
2460      owl_function_error("The filter '%s' does not exist.", argv[1]);
2461      return;
2462    }
2463    if (owl_util_string_to_color(argv[3])==-1) {
2464      owl_function_error("The color '%s' is not available.", argv[3]);
2465      return;
2466    }
2467    owl_filter_set_fgcolor(f, owl_util_string_to_color(argv[3]));
2468    owl_global_set_needrefresh(&g);
2469    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2470    return;
2471  }
2472  if (argc==4 && !strcmp(argv[2], "-b")) {
2473    f=owl_global_get_filter(&g, argv[1]);
2474    if (!f) {
2475      owl_function_error("The filter '%s' does not exist.", argv[1]);
2476      return;
2477    }
2478    if (owl_util_string_to_color(argv[3])==-1) {
2479      owl_function_error("The color '%s' is not available.", argv[3]);
2480      return;
2481    }
2482    owl_filter_set_bgcolor(f, owl_util_string_to_color(argv[3]));
2483    owl_global_set_needrefresh(&g);
2484    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2485    return;
2486  }
2487
2488  /* create the filter and check for errors */
2489  f=owl_malloc(sizeof(owl_filter));
2490  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2491  if (ret==-1) {
2492    owl_free(f);
2493    owl_function_error("Invalid filter");
2494    return;
2495  }
2496
2497  /* if the named filter is in use by the current view, remember it */
2498  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2499    inuse=1;
2500  }
2501
2502  /* if the named filter already exists, nuke it */
2503  if (owl_global_get_filter(&g, argv[1])) {
2504    owl_global_remove_filter(&g, argv[1]);
2505  }
2506
2507  /* add the filter */
2508  owl_global_add_filter(&g, f);
2509
2510  /* if it was in use by the current view then update */
2511  if (inuse) {
2512    owl_function_change_currentview_filter(argv[1]);
2513  }
2514  owl_global_set_needrefresh(&g);
2515  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2516}
2517
2518/* If 'filtername' does not start with 'not-' create a filter named
2519 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2520 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2521 * 'filtername' begins with 'not-' and a filter 'filtername' already
2522 * exists, then do nothing.  If the filter 'filtername' does not
2523 * exist, create it and define it as 'not filter <filtername>'
2524 *
2525 * Returns the name of the negated filter, which the caller must free.
2526 */
2527char *owl_function_create_negative_filter(char *filtername)
2528{
2529  char *newname;
2530  owl_filter *tmpfilt;
2531  char *argv[5];
2532
2533  owl_function_debugmsg("owl_function_create_negative_filter");
2534 
2535  if (!strncmp(filtername, "not-", 4)) {
2536    newname=owl_strdup(filtername+4);
2537  } else {
2538    newname=owl_sprintf("not-%s", filtername);
2539  }
2540
2541  tmpfilt=owl_global_get_filter(&g, newname);
2542  if (!tmpfilt) {
2543    argv[0]="filter"; /* anything is fine here */
2544    argv[1]=newname;
2545    argv[2]="not";
2546    argv[3]="filter";
2547    argv[4]=filtername;
2548    owl_function_create_filter(5, argv);
2549  }
2550
2551  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2552  return(newname);
2553}
2554
2555void owl_function_show_filters()
2556{
2557  owl_list *l;
2558  owl_filter *f;
2559  int i, j;
2560  owl_fmtext fm;
2561
2562  owl_fmtext_init_null(&fm);
2563
2564  l=owl_global_get_filterlist(&g);
2565  j=owl_list_get_size(l);
2566
2567  owl_fmtext_append_bold(&fm, "Filters:\n");
2568
2569  for (i=0; i<j; i++) {
2570    f=owl_list_get_element(l, i);
2571    owl_fmtext_append_normal(&fm, "   ");
2572    if (owl_global_get_hascolors(&g)) {
2573      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_fgcolor(f), owl_filter_get_bgcolor(f));
2574    } else {
2575      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2576    }
2577    owl_fmtext_append_normal(&fm, "\n");
2578  }
2579  owl_function_popless_fmtext(&fm);
2580  owl_fmtext_free(&fm);
2581}
2582
2583void owl_function_show_filter(char *name)
2584{
2585  owl_filter *f;
2586  char buff[5000];
2587
2588  f=owl_global_get_filter(&g, name);
2589  if (!f) {
2590    owl_function_error("There is no filter named %s", name);
2591    return;
2592  }
2593  owl_filter_print(f, buff);
2594  owl_function_popless_text(buff);
2595}
2596
2597void owl_function_show_zpunts()
2598{
2599  owl_filter *f;
2600  owl_list *fl;
2601  char buff[5000];
2602  owl_fmtext fm;
2603  int i, j;
2604
2605  owl_fmtext_init_null(&fm);
2606
2607  fl=owl_global_get_puntlist(&g);
2608  j=owl_list_get_size(fl);
2609  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2610
2611  for (i=0; i<j; i++) {
2612    f=owl_list_get_element(fl, i);
2613    owl_filter_print(f, buff);
2614    owl_fmtext_append_normal(&fm, buff);
2615  }
2616  owl_function_popless_fmtext(&fm);
2617  owl_fmtext_free(&fm);
2618}
2619
2620/* Create a filter for a class, instance if one doesn't exist.  If
2621 * instance is NULL then catch all messgaes in the class.  Returns the
2622 * name of the filter, which the caller must free.
2623 */
2624char *owl_function_classinstfilt(char *c, char *i) 
2625{
2626  owl_list *fl;
2627  owl_filter *f;
2628  char *argbuff, *filtname;
2629  char *tmpclass, *tmpinstance = NULL;
2630  char *class, *instance = NULL;
2631  int len;
2632
2633  class = owl_util_baseclass(c);
2634  if(i) {
2635    instance = owl_util_baseclass(i);
2636  }
2637
2638  fl=owl_global_get_filterlist(&g);
2639
2640  /* name for the filter */
2641  len=strlen(class)+30;
2642  if (instance) len+=strlen(instance);
2643  filtname=owl_malloc(len);
2644  if (!instance) {
2645    sprintf(filtname, "class-%s", class);
2646  } else {
2647    sprintf(filtname, "class-%s-instance-%s", class, instance);
2648  }
2649  /* downcase it */
2650  downstr(filtname);
2651  /* turn spaces into dots */
2652  owl_text_tr(filtname, ' ', '.');
2653 
2654  /* if it already exists then go with it.  This lets users override */
2655  if (owl_global_get_filter(&g, filtname)) {
2656    return(filtname);
2657  }
2658
2659  /* create the new filter */
2660  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2661  owl_text_tr(tmpclass, ' ', '.');
2662  if (instance) {
2663    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2664    owl_text_tr(tmpinstance, ' ', '.');
2665  }
2666  len = strlen(tmpclass);
2667  if(tmpinstance) len += strlen(tmpinstance);
2668  len += 60;
2669  argbuff = owl_malloc(len);
2670  sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
2671  if (tmpinstance) {
2672    sprintf(argbuff, "%s and ( instance ^%s(\\.d)*$ )", argbuff, tmpinstance);
2673  }
2674  owl_free(tmpclass);
2675  if (tmpinstance) owl_free(tmpinstance);
2676
2677  f=owl_malloc(sizeof(owl_filter));
2678  owl_filter_init_fromstring(f, filtname, argbuff);
2679
2680  /* add it to the global list */
2681  owl_global_add_filter(&g, f);
2682
2683  owl_free(argbuff);
2684  owl_free(class);
2685  if (instance) {
2686    owl_free(instance);
2687  }
2688  return(filtname);
2689}
2690
2691/* Create a filter for personal zephyrs to or from the specified
2692 * zephyr user.  Includes login/logout notifications for the user.
2693 * The name of the filter will be 'user-<user>'.  If a filter already
2694 * exists with this name, no new filter will be created.  This allows
2695 * the configuration to override this function.  Returns the name of
2696 * the filter, which the caller must free.
2697 */
2698char *owl_function_zuserfilt(char *user)
2699{
2700  owl_filter *f;
2701  char *argbuff, *longuser, *shortuser, *filtname;
2702
2703  /* stick the local realm on if it's not there */
2704  longuser=long_zuser(user);
2705  shortuser=short_zuser(user);
2706
2707  /* name for the filter */
2708  filtname=owl_malloc(strlen(shortuser)+20);
2709  sprintf(filtname, "user-%s", shortuser);
2710
2711  /* if it already exists then go with it.  This lets users override */
2712  if (owl_global_get_filter(&g, filtname)) {
2713    return(owl_strdup(filtname));
2714  }
2715
2716  /* create the new-internal filter */
2717  f=owl_malloc(sizeof(owl_filter));
2718
2719  argbuff=owl_malloc(strlen(longuser)+1000);
2720  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2721  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2722  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
2723
2724  owl_filter_init_fromstring(f, filtname, argbuff);
2725
2726  /* add it to the global list */
2727  owl_global_add_filter(&g, f);
2728
2729  /* free stuff */
2730  owl_free(argbuff);
2731  owl_free(longuser);
2732  owl_free(shortuser);
2733
2734  return(filtname);
2735}
2736
2737/* Create a filter for AIM IM messages to or from the specified
2738 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2739 * filter already exists with this name, no new filter will be
2740 * created.  This allows the configuration to override this function.
2741 * Returns the name of the filter, which the caller must free.
2742 */
2743char *owl_function_aimuserfilt(char *user)
2744{
2745  owl_filter *f;
2746  char *argbuff, *filtname;
2747
2748  /* name for the filter */
2749  filtname=owl_malloc(strlen(user)+40);
2750  sprintf(filtname, "aimuser-%s", user);
2751
2752  /* if it already exists then go with it.  This lets users override */
2753  if (owl_global_get_filter(&g, filtname)) {
2754    return(owl_strdup(filtname));
2755  }
2756
2757  /* create the new-internal filter */
2758  f=owl_malloc(sizeof(owl_filter));
2759
2760  argbuff=owl_malloc(1000);
2761  sprintf(argbuff,
2762          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2763          user, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), user);
2764
2765  owl_filter_init_fromstring(f, filtname, argbuff);
2766
2767  /* add it to the global list */
2768  owl_global_add_filter(&g, f);
2769
2770  /* free stuff */
2771  owl_free(argbuff);
2772
2773  return(filtname);
2774}
2775
2776char *owl_function_typefilt(char *type)
2777{
2778  owl_filter *f;
2779  char *argbuff, *filtname;
2780
2781  /* name for the filter */
2782  filtname=owl_sprintf("type-%s", type);
2783
2784  /* if it already exists then go with it.  This lets users override */
2785  if (owl_global_get_filter(&g, filtname)) {
2786    return filtname;
2787  }
2788
2789  /* create the new-internal filter */
2790  f=owl_malloc(sizeof(owl_filter));
2791
2792  argbuff = owl_sprintf("type ^%s$", type);
2793
2794  owl_filter_init_fromstring(f, filtname, argbuff);
2795
2796  /* add it to the global list */
2797  owl_global_add_filter(&g, f);
2798
2799  /* free stuff */
2800  owl_free(argbuff);
2801
2802  return filtname;
2803}
2804
2805/* If flag is 1, marks for deletion.  If flag is 0,
2806 * unmarks for deletion. */
2807void owl_function_delete_curview_msgs(int flag)
2808{
2809  owl_view *v;
2810  int i, j;
2811
2812  v=owl_global_get_current_view(&g);
2813  j=owl_view_get_size(v);
2814  for (i=0; i<j; i++) {
2815    if (flag == 1) {
2816      owl_message_mark_delete(owl_view_get_element(v, i));
2817    } else if (flag == 0) {
2818      owl_message_unmark_delete(owl_view_get_element(v, i));
2819    }
2820  }
2821
2822  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2823
2824  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2825}
2826
2827/* Create a filter based on the current message.  Returns the name of
2828 * a filter or null.  The caller must free this name.
2829 *
2830 * if the curmsg is a personal zephyr return a filter name
2831 *    to the zephyr converstaion with that user.
2832 * If the curmsg is a zephyr class message, instance foo, recip *,
2833 *    return a filter name to the class, inst.
2834 * If the curmsg is a zephyr class message and type==0 then
2835 *    return a filter name for just the class.
2836 * If the curmsg is a zephyr class message and type==1 then
2837 *    return a filter name for the class and instance.
2838 * If the curmsg is a personal AIM message returna  filter
2839 *    name to the AIM conversation with that user
2840 */
2841char *owl_function_smartfilter(int type)
2842{
2843  owl_view *v;
2844  owl_message *m;
2845  char *zperson, *filtname=NULL;
2846 
2847  v=owl_global_get_current_view(&g);
2848  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2849
2850  if (!m || owl_view_get_size(v)==0) {
2851    owl_function_error("No message selected\n");
2852    return(NULL);
2853  }
2854
2855  /* very simple handling of admin messages for now */
2856  if (owl_message_is_type_admin(m)) {
2857    return(owl_function_typefilt("admin"));
2858  }
2859
2860  /* very simple handling of loopback messages for now */
2861  if (owl_message_is_type_loopback(m)) {
2862    return(owl_function_typefilt("loopback"));
2863  }
2864
2865  /* aim messages */
2866  if (owl_message_is_type_aim(m)) {
2867    if (owl_message_is_direction_in(m)) {
2868      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2869    } else if (owl_message_is_direction_out(m)) {
2870      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2871    }
2872    return(filtname);
2873  }
2874
2875  /* narrow personal and login messages to the sender or recip as appropriate */
2876  if (owl_message_is_type_zephyr(m)) {
2877    if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2878      if (owl_message_is_direction_in(m)) {
2879        zperson=short_zuser(owl_message_get_sender(m));
2880      } else {
2881        zperson=short_zuser(owl_message_get_recipient(m));
2882      }
2883      filtname=owl_function_zuserfilt(zperson);
2884      owl_free(zperson);
2885      return(filtname);
2886    }
2887
2888    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2889    if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2890      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2891      return(filtname);
2892    }
2893
2894    /* otherwise narrow to the class */
2895    if (type==0) {
2896      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2897    } else if (type==1) {
2898      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2899    }
2900    return(filtname);
2901  }
2902
2903  /* pass it off to perl */
2904  char *argv[1];
2905  if(type) {
2906    argv[0] = "-i";
2907  };
2908  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
2909}
2910
2911void owl_function_smartzpunt(int type)
2912{
2913  /* Starts a zpunt command based on the current class,instance pair.
2914   * If type=0, uses just class.  If type=1, uses instance as well. */
2915  owl_view *v;
2916  owl_message *m;
2917  char *cmd, *cmdprefix, *mclass, *minst;
2918 
2919  v=owl_global_get_current_view(&g);
2920  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2921
2922  if (!m || owl_view_get_size(v)==0) {
2923    owl_function_error("No message selected\n");
2924    return;
2925  }
2926
2927  /* for now we skip admin messages. */
2928  if (owl_message_is_type_admin(m)
2929      || owl_message_is_loginout(m)
2930      || !owl_message_is_type_zephyr(m)) {
2931    owl_function_error("smartzpunt doesn't support this message type.");
2932    return;
2933  }
2934
2935  mclass = owl_message_get_class(m);
2936  minst = owl_message_get_instance(m);
2937  if (!mclass || !*mclass || *mclass==' '
2938      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2939      || (type && (!minst || !*minst|| *minst==' '))) {
2940    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2941                         mclass, minst);
2942  } else {
2943    cmdprefix = "start-command zpunt ";
2944    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2945    strcpy(cmd, cmdprefix);
2946    strcat(cmd, owl_getquoting(mclass));
2947    strcat(cmd, mclass);
2948    strcat(cmd, owl_getquoting(mclass));
2949    if (type) {
2950      strcat(cmd, " ");
2951      strcat(cmd, owl_getquoting(minst));
2952      strcat(cmd, minst);
2953      strcat(cmd, owl_getquoting(minst));
2954    } else {
2955      strcat(cmd, " *");
2956    }
2957    owl_function_command(cmd);
2958    owl_free(cmd);
2959  }
2960}
2961
2962/* Set the color of the current view's filter to
2963 * be 'color'
2964 */
2965void owl_function_color_current_filter(char *fgcolor, char *bgcolor)
2966{
2967  char *name;
2968
2969  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2970  owl_function_color_filter(name, fgcolor, bgcolor);
2971}
2972
2973/* Set the color of the filter 'filter' to be 'color'.  If the color
2974 * name does not exist, return -1, if the filter does not exist or is
2975 * the "all" filter, return -2.  Return 0 on success
2976 */
2977int owl_function_color_filter(char *filtname, char *fgcolor, char *bgcolor)
2978{
2979  owl_filter *f;
2980
2981  f=owl_global_get_filter(&g, filtname);
2982  if (!f) {
2983    owl_function_error("Unknown filter");
2984    return(-2);
2985  }
2986
2987  /* don't touch the all filter */
2988  if (!strcmp(filtname, "all")) {
2989    owl_function_error("You may not change the 'all' filter.");
2990    return(-2);
2991  }
2992
2993  if (owl_util_string_to_color(fgcolor)==-1) {
2994    owl_function_error("No color named '%s' avilable.", fgcolor);
2995    return(-1);
2996  }
2997
2998
2999  if (bgcolor != NULL) {
3000    if (owl_util_string_to_color(bgcolor)==-1) {
3001      owl_function_error("No color named '%s' avilable.", bgcolor);
3002      return(-1);
3003    }
3004    owl_filter_set_bgcolor(f, owl_util_string_to_color(bgcolor));
3005  }
3006  owl_filter_set_fgcolor(f, owl_util_string_to_color(fgcolor));
3007 
3008  owl_global_set_needrefresh(&g);
3009  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3010  return(0);
3011}
3012
3013void owl_function_show_colors()
3014{
3015  owl_fmtext fm;
3016
3017  owl_fmtext_init_null(&fm);
3018  owl_fmtext_append_normal(&fm, "default: ");
3019  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
3020
3021  owl_fmtext_append_normal(&fm,"red:      ");
3022  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED, OWL_COLOR_DEFAULT);
3023
3024  owl_fmtext_append_normal(&fm,"green:    ");
3025  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN, OWL_COLOR_DEFAULT);
3026
3027  owl_fmtext_append_normal(&fm,"yellow:   ");
3028  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW, OWL_COLOR_DEFAULT);
3029
3030  owl_fmtext_append_normal(&fm,"blue:     ");
3031  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE, OWL_COLOR_DEFAULT);
3032
3033  owl_fmtext_append_normal(&fm,"magenta:  ");
3034  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA, OWL_COLOR_DEFAULT);
3035
3036  owl_fmtext_append_normal(&fm,"cyan:     ");
3037  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN, OWL_COLOR_DEFAULT);
3038
3039  owl_fmtext_append_normal(&fm,"white:    ");
3040  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE, OWL_COLOR_DEFAULT);
3041
3042  owl_function_popless_fmtext(&fm);
3043  owl_fmtext_free(&fm);
3044}
3045
3046/* add the given class, inst, recip to the punt list for filtering.
3047 *   if direction==0 then punt
3048 *   if direction==1 then unpunt
3049 */
3050void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
3051{
3052  owl_filter *f;
3053  owl_list *fl;
3054  char *buff;
3055  char *quoted;
3056  int ret, i, j;
3057
3058  fl=owl_global_get_puntlist(&g);
3059
3060  /* first, create the filter */
3061  f=malloc(sizeof(owl_filter));
3062  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
3063  strcpy(buff, "class");
3064  if (!strcmp(class, "*")) {
3065    strcat(buff, " .*");
3066  } else {
3067    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3068    owl_text_tr(quoted, ' ', '.');
3069    sprintf(buff, "%s ^(un)*%s(\\.d)*$", buff, quoted);
3070    owl_free(quoted);
3071  }
3072  if (!strcmp(inst, "*")) {
3073    strcat(buff, " and instance .*");
3074  } else {
3075    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3076    owl_text_tr(quoted, ' ', '.');
3077    sprintf(buff, "%s and instance ^(un)*%s(\\.d)*$", buff, quoted);
3078    owl_free(quoted);
3079  }
3080  if (strcmp(recip, "*")) {
3081    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3082    owl_text_tr(quoted, ' ', '.');
3083    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
3084    owl_free(quoted);
3085  }
3086 
3087  owl_function_debugmsg("About to filter %s", buff);
3088  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
3089  owl_free(buff);
3090  if (ret) {
3091    owl_function_error("Error creating filter for zpunt");
3092    owl_filter_free(f);
3093    return;
3094  }
3095
3096  /* Check for an identical filter */
3097  j=owl_list_get_size(fl);
3098  for (i=0; i<j; i++) {
3099    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
3100      /* if we're punting, then just silently bow out on this duplicate */
3101      if (direction==0) {
3102        owl_filter_free(f);
3103        return;
3104      }
3105
3106      /* if we're unpunting, then remove this filter from the puntlist */
3107      if (direction==1) {
3108        owl_filter_free(owl_list_get_element(fl, i));
3109        owl_list_remove_element(fl, i);
3110        return;
3111      }
3112    }
3113  }
3114
3115  /* If we're punting, add the filter to the global punt list */
3116  if (direction==0) {
3117    owl_list_append_element(fl, f);
3118  }
3119}
3120
3121void owl_function_activate_keymap(char *keymap)
3122{
3123  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
3124    owl_function_error("Unable to activate keymap '%s'", keymap);
3125  }
3126}
3127
3128void owl_function_show_keymaps()
3129{
3130  owl_list l;
3131  owl_fmtext fm;
3132  owl_keymap *km;
3133  owl_keyhandler *kh;
3134  int i, numkm;
3135  char *kmname;
3136
3137  kh = owl_global_get_keyhandler(&g);
3138  owl_fmtext_init_null(&fm);
3139  owl_fmtext_append_bold(&fm, "Keymaps:   ");
3140  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
3141  owl_keyhandler_get_keymap_names(kh, &l);
3142  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
3143  owl_fmtext_append_normal(&fm, "\n");
3144
3145  numkm = owl_list_get_size(&l);
3146  for (i=0; i<numkm; i++) {
3147    kmname = owl_list_get_element(&l, i);
3148    km = owl_keyhandler_get_keymap(kh, kmname);
3149    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
3150    owl_keymap_get_details(km, &fm);   
3151  }
3152  owl_fmtext_append_normal(&fm, "\n");
3153 
3154  owl_function_popless_fmtext(&fm);
3155  owl_keyhandler_keymap_namelist_free(&l);
3156  owl_fmtext_free(&fm);
3157}
3158
3159char *owl_function_keymap_summary(void *name)
3160{
3161  owl_keymap *km
3162    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3163  if (km) return owl_keymap_summary(km);
3164  else return(NULL);
3165}
3166
3167/* TODO: implement for real */
3168void owl_function_show_keymap(char *name)
3169{
3170  owl_fmtext fm;
3171  owl_keymap *km;
3172
3173  owl_fmtext_init_null(&fm);
3174  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3175  if (km) {
3176    owl_keymap_get_details(km, &fm);
3177  } else {
3178    owl_fmtext_append_normal(&fm, "No such keymap...\n");
3179  } 
3180  owl_function_popless_fmtext(&fm);
3181  owl_fmtext_free(&fm);
3182}
3183
3184void owl_function_help_for_command(char *cmdname)
3185{
3186  owl_fmtext fm;
3187
3188  owl_fmtext_init_null(&fm);
3189  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3190  owl_function_popless_fmtext(&fm); 
3191  owl_fmtext_free(&fm);
3192}
3193
3194void owl_function_search_start(char *string, int direction)
3195{
3196  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3197  owl_global_set_search_active(&g, string);
3198  owl_function_search_helper(0, direction);
3199}
3200
3201void owl_function_search_continue(int direction)
3202{
3203  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3204  owl_function_search_helper(1, direction);
3205}
3206
3207void owl_function_search_helper(int mode, int direction)
3208{
3209  /* move to a message that contains the string.  If direction is
3210   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3211   * OWL_DIRECTION_UPWARDS then search backwards.
3212   *
3213   * If mode==0 then it will stay on the current message if it
3214   * contains the string.
3215   */
3216
3217  owl_view *v;
3218  int viewsize, i, curmsg, start;
3219  owl_message *m;
3220
3221  v=owl_global_get_current_view(&g);
3222  viewsize=owl_view_get_size(v);
3223  curmsg=owl_global_get_curmsg(&g);
3224 
3225  if (viewsize==0) {
3226    owl_function_error("No messages present");
3227    return;
3228  }
3229
3230  if (mode==0) {
3231    start=curmsg;
3232  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3233    start=curmsg+1;
3234  } else {
3235    start=curmsg-1;
3236  }
3237
3238  /* bounds check */
3239  if (start>=viewsize || start<0) {
3240    owl_function_error("No further matches found");
3241    return;
3242  }
3243
3244  for (i=start; i<viewsize && i>=0;) {
3245    m=owl_view_get_element(v, i);
3246    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3247      owl_global_set_curmsg(&g, i);
3248      owl_function_calculate_topmsg(direction);
3249      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3250      if (direction==OWL_DIRECTION_DOWNWARDS) {
3251        owl_global_set_direction_downwards(&g);
3252      } else {
3253        owl_global_set_direction_upwards(&g);
3254      }
3255      return;
3256    }
3257    if (direction==OWL_DIRECTION_DOWNWARDS) {
3258      i++;
3259    } else {
3260      i--;
3261    }
3262  }
3263  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3264  owl_function_error("No matches found");
3265}
3266
3267/* strips formatting from ztext and returns the unformatted text.
3268 * caller is responsible for freeing. */
3269char *owl_function_ztext_stylestrip(char *zt)
3270{
3271  owl_fmtext fm;
3272  char *plaintext;
3273
3274  owl_fmtext_init_null(&fm);
3275  owl_fmtext_append_ztext(&fm, zt);
3276  plaintext = owl_fmtext_print_plain(&fm);
3277  owl_fmtext_free(&fm);
3278  return(plaintext);
3279}
3280
3281/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3282void owl_function_buddylist(int aim, int zephyr, char *filename)
3283{
3284  int i, j, x, idle;
3285  owl_fmtext fm;
3286  owl_buddylist *bl;
3287  owl_buddy *b;
3288  owl_list anyone;
3289  char *foo, *timestr;
3290#ifdef HAVE_LIBZEPHYR
3291  char *tmp, *user, *line;
3292  ZLocations_t location[200];
3293  int numlocs, ret;
3294#endif
3295
3296  owl_fmtext_init_null(&fm);
3297
3298  /* AIM first */
3299  if (aim && owl_global_is_aimloggedin(&g)) {
3300    bl=owl_global_get_buddylist(&g);
3301
3302    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3303    /* we're assuming AIM for now */
3304    j=owl_buddylist_get_size(bl);
3305    for (i=0; i<j; i++) {
3306      b=owl_buddylist_get_buddy_n(bl, i);
3307      idle=owl_buddy_get_idle_time(b);
3308      if (idle!=0) {
3309        timestr=owl_util_minutes_to_timestr(idle);
3310      } else {
3311        timestr=owl_strdup("");
3312      }
3313      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3314      owl_fmtext_append_normal(&fm, foo);
3315      owl_free(timestr);
3316      owl_free(foo);
3317    }
3318  }
3319
3320#ifdef HAVE_LIBZEPHYR
3321  if (zephyr) {
3322    if(!owl_global_is_havezephyr(&g)) {
3323      owl_function_error("Zephyr currently not available.");
3324    } else {
3325      owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3326      owl_list_create(&anyone);
3327      ret=owl_zephyr_get_anyone_list(&anyone, filename);
3328      if (ret) {
3329        owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3330      } else {
3331        j=owl_list_get_size(&anyone);
3332        for (i=0; i<j; i++) {
3333          user=owl_list_get_element(&anyone, i);
3334          ret=ZLocateUser(user, &numlocs, ZAUTH);
3335          if (ret!=ZERR_NONE) {
3336            owl_function_error("Error getting location for %s", user);
3337            continue;
3338          }
3339
3340          numlocs=200;
3341          ret=ZGetLocations(location, &numlocs);
3342          if (ret==0) {
3343            for (x=0; x<numlocs; x++) {
3344              line=malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3345              tmp=short_zuser(user);
3346              sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3347                      tmp,
3348                      location[x].host,
3349                      location[x].tty,
3350                      location[x].time);
3351              owl_fmtext_append_normal(&fm, line);
3352              owl_free(tmp);
3353              owl_free(line);
3354            }
3355            if (numlocs>=200) {
3356              owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3357            }
3358          }
3359        }
3360      }
3361      owl_list_free_all(&anyone, owl_free);
3362    } 
3363  }
3364#endif
3365
3366  if(aim && zephyr) {
3367      if(owl_perlconfig_is_function("BarnOwl::Hooks::_get_blist")) {
3368          char * perlblist = owl_perlconfig_execute("BarnOwl::Hooks::_get_blist()");
3369          if(perlblist) {
3370              owl_fmtext_append_ztext(&fm, perlblist);
3371              owl_free(perlblist);
3372          }
3373      }
3374  }
3375 
3376  owl_function_popless_fmtext(&fm);
3377  owl_fmtext_free(&fm);
3378}
3379
3380/* Dump messages in the current view to the file 'filename'. */
3381void owl_function_dump(char *filename) 
3382{
3383  int i, j, count;
3384  owl_message *m;
3385  owl_view *v;
3386  FILE *file;
3387
3388  v=owl_global_get_current_view(&g);
3389
3390  /* in the future make it ask yes/no */
3391  /*
3392  ret=stat(filename, &sbuf);
3393  if (!ret) {
3394    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3395    if (!ret) return;
3396  }
3397  */
3398
3399  file=fopen(filename, "w");
3400  if (!file) {
3401    owl_function_error("Error opening file");
3402    return;
3403  }
3404
3405  count=0;
3406  j=owl_view_get_size(v);
3407  for (i=0; i<j; i++) {
3408    m=owl_view_get_element(v, i);
3409    fputs(owl_message_get_text(m), file);
3410  }
3411  fclose(file);
3412  owl_function_makemsg("Messages dumped to %s", filename);
3413}
3414
3415void owl_function_do_newmsgproc(void)
3416{
3417  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3418    /* if there's a process out there, we need to check on it */
3419    if (owl_global_get_newmsgproc_pid(&g)) {
3420      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3421      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3422      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3423      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3424        /* it exited */
3425        owl_global_set_newmsgproc_pid(&g, 0);
3426        owl_function_debugmsg("newmsgproc exited");
3427      } else {
3428        owl_function_debugmsg("newmsgproc did not exit");
3429      }
3430    }
3431   
3432    /* if it exited, fork & exec a new one */
3433    if (owl_global_get_newmsgproc_pid(&g)==0) {
3434      int i, myargc;
3435      i=fork();
3436      if (i) {
3437        /* parent set the child's pid */
3438        owl_global_set_newmsgproc_pid(&g, i);
3439        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3440      } else {
3441        /* child exec's the program */
3442        char **parsed;
3443        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3444        if (myargc < 0) {
3445          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3446        }
3447        if (myargc <= 0) {
3448          _exit(127);
3449        }
3450        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3451        parsed[myargc] = NULL;
3452       
3453        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3454       
3455        execvp(parsed[0], parsed);
3456       
3457       
3458        /* was there an error exec'ing? */
3459        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3460                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3461        _exit(127);
3462      }
3463    }
3464  }
3465}
3466
3467/* print the xterm escape sequence to raise the window */
3468void owl_function_xterm_raise(void)
3469{
3470  printf("\033[5t");
3471}
3472
3473/* print the xterm escape sequence to deiconify the window */
3474void owl_function_xterm_deiconify(void)
3475{
3476  printf("\033[1t");
3477}
3478
3479/* Add the specified command to the startup file.  Eventually this
3480 * should be clever, and rewriting settings that will obviosly
3481 * override earlier settings with 'set' 'bindkey' and 'alias'
3482 * commands.  For now though we just remove any line that would
3483 * duplicate this one and then append this line to the end of
3484 * startupfile.
3485 */
3486void owl_function_addstartup(char *buff)
3487{
3488  FILE *file;
3489  char *filename;
3490
3491  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3492  file=fopen(filename, "a");
3493  if (!file) {
3494    owl_function_error("Error opening startupfile for new command");
3495    owl_free(filename);
3496    return;
3497  }
3498
3499  /* delete earlier copies */
3500  owl_util_file_deleteline(filename, buff, 1);
3501  owl_free(filename);
3502
3503  /* add this line */
3504  fprintf(file, "%s\n", buff);
3505
3506  fclose(file);
3507}
3508
3509/* Remove the specified command from the startup file. */
3510void owl_function_delstartup(char *buff)
3511{
3512  char *filename;
3513  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3514  owl_util_file_deleteline(filename, buff, 1);
3515  owl_free(filename);
3516}
3517
3518/* Execute owl commands from the given filename.  If the filename
3519 * is NULL, use the default owl startup commands file.
3520 */
3521void owl_function_source(char *filename)
3522{
3523  FILE *file;
3524  char buff[LINE];
3525
3526  if (!filename) {
3527    filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3528    file=fopen(filename, "r");
3529    owl_free(filename);
3530  } else {
3531    file=fopen(filename, "r");
3532  }
3533  if (!file) {
3534    /* just fail silently if it doesn't exist */
3535    return;
3536  }
3537  while (fgets(buff, LINE, file)!=NULL) {
3538    if (buff[0] == '#') continue;
3539    buff[strlen(buff)-1]='\0';
3540    owl_function_command(buff);
3541  }
3542  fclose(file);
3543}
3544
3545void owl_function_change_style(owl_view *v, char *stylename)
3546{
3547  owl_style *s;
3548
3549  s=owl_global_get_style_by_name(&g, stylename);
3550  if (!s) {
3551    owl_function_error("No style named %s", stylename);
3552    return;
3553  }
3554  owl_view_set_style(v, s);
3555  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3556  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3557  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3558}
3559
3560void owl_function_toggleoneline()
3561{
3562  owl_view *v;
3563  owl_style *s;
3564
3565  v=owl_global_get_current_view(&g);
3566  s=owl_view_get_style(v);
3567
3568  if (!owl_style_matches_name(s, "oneline")) {
3569    owl_function_change_style(v, "oneline");
3570  } else {
3571    owl_function_change_style(v, owl_global_get_default_style(&g));
3572  }
3573
3574  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3575  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3576  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3577}
3578
3579void owl_function_error(char *fmt, ...)
3580{
3581  va_list ap;
3582  char buff[2048], buff2[2048];
3583  char *date;
3584  time_t now;
3585
3586  now=time(NULL);
3587  date=owl_strdup(ctime(&now));
3588  date[strlen(date)-1]='\0';
3589
3590  va_start(ap, fmt);
3591
3592  vsnprintf(buff, 2048, fmt, ap);
3593  sprintf(buff2, "%s %s", date, buff);
3594  owl_function_debugmsg("ERROR: %s", buff);
3595  if (owl_global_get_curs_msgwin(&g)) {
3596    werase(owl_global_get_curs_msgwin(&g));
3597    waddstr(owl_global_get_curs_msgwin(&g), buff); 
3598    wnoutrefresh(owl_global_get_curs_msgwin(&g));
3599    owl_global_set_needrefresh(&g);
3600  }
3601  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3602  va_end(ap);
3603  owl_free(date);
3604}
3605
3606void owl_function_showerrs()
3607{
3608  owl_fmtext fm;
3609
3610  owl_fmtext_init_null(&fm);
3611  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3612  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3613  owl_function_popless_fmtext(&fm);
3614}
3615
3616void owl_function_makemsg(char *fmt, ...)
3617{
3618  va_list ap;
3619  char buff[2048];
3620
3621  if (!owl_global_get_curs_msgwin(&g)) return;
3622
3623  va_start(ap, fmt);
3624  werase(owl_global_get_curs_msgwin(&g));
3625 
3626  vsnprintf(buff, 2048, fmt, ap);
3627  owl_function_debugmsg("makemsg: %s", buff);
3628  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3629  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3630  owl_global_set_needrefresh(&g);
3631  va_end(ap);
3632}
3633
3634/* get locations for everyone in .anyone.  If 'notify' is '1' then
3635 * send a pseudo login or logout message for everyone not in sync with
3636 * the global zephyr buddy list.  The list is updated regardless of
3637 * the status of 'notify'.
3638 */
3639void owl_function_zephyr_buddy_check(int notify)
3640{
3641#ifdef HAVE_LIBZEPHYR
3642  int i, j;
3643  owl_list anyone;
3644  owl_message *m;
3645  owl_zbuddylist *zbl;
3646  char *user;
3647  ZLocations_t location[200];
3648  int numlocs, ret;
3649
3650  zbl=owl_global_get_zephyr_buddylist(&g);
3651
3652  owl_list_create(&anyone);
3653  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3654
3655  j=owl_list_get_size(&anyone);
3656  for (i=0; i<j; i++) {
3657    user=owl_list_get_element(&anyone, i);
3658    ret=ZLocateUser(user, &numlocs, ZAUTH);
3659    if (ret!=ZERR_NONE) {
3660      owl_function_error("Error getting location for %s", user);
3661      continue;
3662    }
3663    numlocs=200;
3664    ret=ZGetLocations(location, &numlocs);
3665    if (ret==0) {
3666      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3667        /* Send a PSEUDO LOGIN! */
3668        if (notify) {
3669          m=owl_malloc(sizeof(owl_message));
3670          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3671          owl_global_messagequeue_addmsg(&g, m);
3672        }
3673        owl_zbuddylist_adduser(zbl, user);
3674        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3675      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3676        /* I don't think this ever happens (if there are 0 locations we should get an error from
3677         * ZGetLocations)
3678         */
3679        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3680      }
3681    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3682      /* Send a PSEUDO LOGOUT! */
3683      if (notify) {
3684        m=owl_malloc(sizeof(owl_message));
3685        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3686        owl_global_messagequeue_addmsg(&g, m);
3687      }
3688      owl_zbuddylist_deluser(zbl, user);
3689      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3690    }
3691  }
3692
3693  owl_list_free_all(&anyone, owl_free);
3694#endif
3695}
3696
3697void owl_function_aimsearch_results(char *email, owl_list *namelist)
3698{
3699  owl_fmtext fm;
3700  int i, j;
3701
3702  owl_fmtext_init_null(&fm);
3703  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3704  owl_fmtext_append_normal(&fm, email);
3705  owl_fmtext_append_normal(&fm, ":\n");
3706
3707  j=owl_list_get_size(namelist);
3708  for (i=0; i<j; i++) {
3709    owl_fmtext_append_normal(&fm, "  ");
3710    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3711    owl_fmtext_append_normal(&fm, "\n");
3712  }
3713
3714  owl_function_popless_fmtext(&fm);
3715  owl_fmtext_free(&fm);
3716}
Note: See TracBrowser for help on using the repository browser.