source: functions.c @ af9b92e

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since af9b92e was af9b92e, checked in by Nelson Elhage <nelhage@mit.edu>, 17 years ago
Escape aim users' names in smartfilters.
  • Property mode set to 100644
File size: 99.7 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  char *escuser;
2748
2749  /* name for the filter */
2750  filtname=owl_malloc(strlen(user)+40);
2751  sprintf(filtname, "aimuser-%s", user);
2752
2753  /* if it already exists then go with it.  This lets users override */
2754  if (owl_global_get_filter(&g, filtname)) {
2755    return(owl_strdup(filtname));
2756  }
2757
2758  /* create the new-internal filter */
2759  f=owl_malloc(sizeof(owl_filter));
2760
2761  escuser = owl_text_quote(user, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2762
2763  argbuff=owl_malloc(1000);
2764  sprintf(argbuff,
2765          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2766          escuser, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), escuser);
2767
2768  owl_filter_init_fromstring(f, filtname, argbuff);
2769
2770  /* add it to the global list */
2771  owl_global_add_filter(&g, f);
2772
2773  /* free stuff */
2774  owl_free(argbuff);
2775  owl_free(escuser);
2776
2777  return(filtname);
2778}
2779
2780char *owl_function_typefilt(char *type)
2781{
2782  owl_filter *f;
2783  char *argbuff, *filtname;
2784
2785  /* name for the filter */
2786  filtname=owl_sprintf("type-%s", type);
2787
2788  /* if it already exists then go with it.  This lets users override */
2789  if (owl_global_get_filter(&g, filtname)) {
2790    return filtname;
2791  }
2792
2793  /* create the new-internal filter */
2794  f=owl_malloc(sizeof(owl_filter));
2795
2796  argbuff = owl_sprintf("type ^%s$", type);
2797
2798  owl_filter_init_fromstring(f, filtname, argbuff);
2799
2800  /* add it to the global list */
2801  owl_global_add_filter(&g, f);
2802
2803  /* free stuff */
2804  owl_free(argbuff);
2805
2806  return filtname;
2807}
2808
2809/* If flag is 1, marks for deletion.  If flag is 0,
2810 * unmarks for deletion. */
2811void owl_function_delete_curview_msgs(int flag)
2812{
2813  owl_view *v;
2814  int i, j;
2815
2816  v=owl_global_get_current_view(&g);
2817  j=owl_view_get_size(v);
2818  for (i=0; i<j; i++) {
2819    if (flag == 1) {
2820      owl_message_mark_delete(owl_view_get_element(v, i));
2821    } else if (flag == 0) {
2822      owl_message_unmark_delete(owl_view_get_element(v, i));
2823    }
2824  }
2825
2826  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2827
2828  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2829}
2830
2831/* Create a filter based on the current message.  Returns the name of
2832 * a filter or null.  The caller must free this name.
2833 *
2834 * if the curmsg is a personal zephyr return a filter name
2835 *    to the zephyr converstaion with that user.
2836 * If the curmsg is a zephyr class message, instance foo, recip *,
2837 *    return a filter name to the class, inst.
2838 * If the curmsg is a zephyr class message and type==0 then
2839 *    return a filter name for just the class.
2840 * If the curmsg is a zephyr class message and type==1 then
2841 *    return a filter name for the class and instance.
2842 * If the curmsg is a personal AIM message returna  filter
2843 *    name to the AIM conversation with that user
2844 */
2845char *owl_function_smartfilter(int type)
2846{
2847  owl_view *v;
2848  owl_message *m;
2849  char *zperson, *filtname=NULL;
2850 
2851  v=owl_global_get_current_view(&g);
2852  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2853
2854  if (!m || owl_view_get_size(v)==0) {
2855    owl_function_error("No message selected\n");
2856    return(NULL);
2857  }
2858
2859  /* very simple handling of admin messages for now */
2860  if (owl_message_is_type_admin(m)) {
2861    return(owl_function_typefilt("admin"));
2862  }
2863
2864  /* very simple handling of loopback messages for now */
2865  if (owl_message_is_type_loopback(m)) {
2866    return(owl_function_typefilt("loopback"));
2867  }
2868
2869  /* aim messages */
2870  if (owl_message_is_type_aim(m)) {
2871    if (owl_message_is_direction_in(m)) {
2872      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2873    } else if (owl_message_is_direction_out(m)) {
2874      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2875    }
2876    return(filtname);
2877  }
2878
2879  /* narrow personal and login messages to the sender or recip as appropriate */
2880  if (owl_message_is_type_zephyr(m)) {
2881    if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2882      if (owl_message_is_direction_in(m)) {
2883        zperson=short_zuser(owl_message_get_sender(m));
2884      } else {
2885        zperson=short_zuser(owl_message_get_recipient(m));
2886      }
2887      filtname=owl_function_zuserfilt(zperson);
2888      owl_free(zperson);
2889      return(filtname);
2890    }
2891
2892    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2893    if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2894      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2895      return(filtname);
2896    }
2897
2898    /* otherwise narrow to the class */
2899    if (type==0) {
2900      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2901    } else if (type==1) {
2902      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2903    }
2904    return(filtname);
2905  }
2906
2907  /* pass it off to perl */
2908  char *argv[1];
2909  if(type) {
2910    argv[0] = "-i";
2911  };
2912  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
2913}
2914
2915void owl_function_smartzpunt(int type)
2916{
2917  /* Starts a zpunt command based on the current class,instance pair.
2918   * If type=0, uses just class.  If type=1, uses instance as well. */
2919  owl_view *v;
2920  owl_message *m;
2921  char *cmd, *cmdprefix, *mclass, *minst;
2922 
2923  v=owl_global_get_current_view(&g);
2924  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2925
2926  if (!m || owl_view_get_size(v)==0) {
2927    owl_function_error("No message selected\n");
2928    return;
2929  }
2930
2931  /* for now we skip admin messages. */
2932  if (owl_message_is_type_admin(m)
2933      || owl_message_is_loginout(m)
2934      || !owl_message_is_type_zephyr(m)) {
2935    owl_function_error("smartzpunt doesn't support this message type.");
2936    return;
2937  }
2938
2939  mclass = owl_message_get_class(m);
2940  minst = owl_message_get_instance(m);
2941  if (!mclass || !*mclass || *mclass==' '
2942      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2943      || (type && (!minst || !*minst|| *minst==' '))) {
2944    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2945                         mclass, minst);
2946  } else {
2947    cmdprefix = "start-command zpunt ";
2948    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2949    strcpy(cmd, cmdprefix);
2950    strcat(cmd, owl_getquoting(mclass));
2951    strcat(cmd, mclass);
2952    strcat(cmd, owl_getquoting(mclass));
2953    if (type) {
2954      strcat(cmd, " ");
2955      strcat(cmd, owl_getquoting(minst));
2956      strcat(cmd, minst);
2957      strcat(cmd, owl_getquoting(minst));
2958    } else {
2959      strcat(cmd, " *");
2960    }
2961    owl_function_command(cmd);
2962    owl_free(cmd);
2963  }
2964}
2965
2966/* Set the color of the current view's filter to
2967 * be 'color'
2968 */
2969void owl_function_color_current_filter(char *fgcolor, char *bgcolor)
2970{
2971  char *name;
2972
2973  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2974  owl_function_color_filter(name, fgcolor, bgcolor);
2975}
2976
2977/* Set the color of the filter 'filter' to be 'color'.  If the color
2978 * name does not exist, return -1, if the filter does not exist or is
2979 * the "all" filter, return -2.  Return 0 on success
2980 */
2981int owl_function_color_filter(char *filtname, char *fgcolor, char *bgcolor)
2982{
2983  owl_filter *f;
2984
2985  f=owl_global_get_filter(&g, filtname);
2986  if (!f) {
2987    owl_function_error("Unknown filter");
2988    return(-2);
2989  }
2990
2991  /* don't touch the all filter */
2992  if (!strcmp(filtname, "all")) {
2993    owl_function_error("You may not change the 'all' filter.");
2994    return(-2);
2995  }
2996
2997  if (owl_util_string_to_color(fgcolor)==-1) {
2998    owl_function_error("No color named '%s' avilable.", fgcolor);
2999    return(-1);
3000  }
3001
3002
3003  if (bgcolor != NULL) {
3004    if (owl_util_string_to_color(bgcolor)==-1) {
3005      owl_function_error("No color named '%s' avilable.", bgcolor);
3006      return(-1);
3007    }
3008    owl_filter_set_bgcolor(f, owl_util_string_to_color(bgcolor));
3009  }
3010  owl_filter_set_fgcolor(f, owl_util_string_to_color(fgcolor));
3011 
3012  owl_global_set_needrefresh(&g);
3013  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3014  return(0);
3015}
3016
3017void owl_function_show_colors()
3018{
3019  owl_fmtext fm;
3020
3021  owl_fmtext_init_null(&fm);
3022  owl_fmtext_append_normal(&fm, "default: ");
3023  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
3024
3025  owl_fmtext_append_normal(&fm,"red:      ");
3026  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED, OWL_COLOR_DEFAULT);
3027
3028  owl_fmtext_append_normal(&fm,"green:    ");
3029  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN, OWL_COLOR_DEFAULT);
3030
3031  owl_fmtext_append_normal(&fm,"yellow:   ");
3032  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW, OWL_COLOR_DEFAULT);
3033
3034  owl_fmtext_append_normal(&fm,"blue:     ");
3035  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE, OWL_COLOR_DEFAULT);
3036
3037  owl_fmtext_append_normal(&fm,"magenta:  ");
3038  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA, OWL_COLOR_DEFAULT);
3039
3040  owl_fmtext_append_normal(&fm,"cyan:     ");
3041  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN, OWL_COLOR_DEFAULT);
3042
3043  owl_fmtext_append_normal(&fm,"white:    ");
3044  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE, OWL_COLOR_DEFAULT);
3045
3046  owl_function_popless_fmtext(&fm);
3047  owl_fmtext_free(&fm);
3048}
3049
3050/* add the given class, inst, recip to the punt list for filtering.
3051 *   if direction==0 then punt
3052 *   if direction==1 then unpunt
3053 */
3054void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
3055{
3056  owl_filter *f;
3057  owl_list *fl;
3058  char *buff;
3059  char *quoted;
3060  int ret, i, j;
3061
3062  fl=owl_global_get_puntlist(&g);
3063
3064  /* first, create the filter */
3065  f=malloc(sizeof(owl_filter));
3066  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
3067  strcpy(buff, "class");
3068  if (!strcmp(class, "*")) {
3069    strcat(buff, " .*");
3070  } else {
3071    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3072    owl_text_tr(quoted, ' ', '.');
3073    sprintf(buff, "%s ^(un)*%s(\\.d)*$", buff, quoted);
3074    owl_free(quoted);
3075  }
3076  if (!strcmp(inst, "*")) {
3077    strcat(buff, " and instance .*");
3078  } else {
3079    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3080    owl_text_tr(quoted, ' ', '.');
3081    sprintf(buff, "%s and instance ^(un)*%s(\\.d)*$", buff, quoted);
3082    owl_free(quoted);
3083  }
3084  if (strcmp(recip, "*")) {
3085    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3086    owl_text_tr(quoted, ' ', '.');
3087    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
3088    owl_free(quoted);
3089  }
3090 
3091  owl_function_debugmsg("About to filter %s", buff);
3092  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
3093  owl_free(buff);
3094  if (ret) {
3095    owl_function_error("Error creating filter for zpunt");
3096    owl_filter_free(f);
3097    return;
3098  }
3099
3100  /* Check for an identical filter */
3101  j=owl_list_get_size(fl);
3102  for (i=0; i<j; i++) {
3103    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
3104      /* if we're punting, then just silently bow out on this duplicate */
3105      if (direction==0) {
3106        owl_filter_free(f);
3107        return;
3108      }
3109
3110      /* if we're unpunting, then remove this filter from the puntlist */
3111      if (direction==1) {
3112        owl_filter_free(owl_list_get_element(fl, i));
3113        owl_list_remove_element(fl, i);
3114        return;
3115      }
3116    }
3117  }
3118
3119  /* If we're punting, add the filter to the global punt list */
3120  if (direction==0) {
3121    owl_list_append_element(fl, f);
3122  }
3123}
3124
3125void owl_function_activate_keymap(char *keymap)
3126{
3127  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
3128    owl_function_error("Unable to activate keymap '%s'", keymap);
3129  }
3130}
3131
3132void owl_function_show_keymaps()
3133{
3134  owl_list l;
3135  owl_fmtext fm;
3136  owl_keymap *km;
3137  owl_keyhandler *kh;
3138  int i, numkm;
3139  char *kmname;
3140
3141  kh = owl_global_get_keyhandler(&g);
3142  owl_fmtext_init_null(&fm);
3143  owl_fmtext_append_bold(&fm, "Keymaps:   ");
3144  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
3145  owl_keyhandler_get_keymap_names(kh, &l);
3146  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
3147  owl_fmtext_append_normal(&fm, "\n");
3148
3149  numkm = owl_list_get_size(&l);
3150  for (i=0; i<numkm; i++) {
3151    kmname = owl_list_get_element(&l, i);
3152    km = owl_keyhandler_get_keymap(kh, kmname);
3153    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
3154    owl_keymap_get_details(km, &fm);   
3155  }
3156  owl_fmtext_append_normal(&fm, "\n");
3157 
3158  owl_function_popless_fmtext(&fm);
3159  owl_keyhandler_keymap_namelist_free(&l);
3160  owl_fmtext_free(&fm);
3161}
3162
3163char *owl_function_keymap_summary(void *name)
3164{
3165  owl_keymap *km
3166    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3167  if (km) return owl_keymap_summary(km);
3168  else return(NULL);
3169}
3170
3171/* TODO: implement for real */
3172void owl_function_show_keymap(char *name)
3173{
3174  owl_fmtext fm;
3175  owl_keymap *km;
3176
3177  owl_fmtext_init_null(&fm);
3178  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3179  if (km) {
3180    owl_keymap_get_details(km, &fm);
3181  } else {
3182    owl_fmtext_append_normal(&fm, "No such keymap...\n");
3183  } 
3184  owl_function_popless_fmtext(&fm);
3185  owl_fmtext_free(&fm);
3186}
3187
3188void owl_function_help_for_command(char *cmdname)
3189{
3190  owl_fmtext fm;
3191
3192  owl_fmtext_init_null(&fm);
3193  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3194  owl_function_popless_fmtext(&fm); 
3195  owl_fmtext_free(&fm);
3196}
3197
3198void owl_function_search_start(char *string, int direction)
3199{
3200  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3201  owl_global_set_search_active(&g, string);
3202  owl_function_search_helper(0, direction);
3203}
3204
3205void owl_function_search_continue(int direction)
3206{
3207  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3208  owl_function_search_helper(1, direction);
3209}
3210
3211void owl_function_search_helper(int mode, int direction)
3212{
3213  /* move to a message that contains the string.  If direction is
3214   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3215   * OWL_DIRECTION_UPWARDS then search backwards.
3216   *
3217   * If mode==0 then it will stay on the current message if it
3218   * contains the string.
3219   */
3220
3221  owl_view *v;
3222  int viewsize, i, curmsg, start;
3223  owl_message *m;
3224
3225  v=owl_global_get_current_view(&g);
3226  viewsize=owl_view_get_size(v);
3227  curmsg=owl_global_get_curmsg(&g);
3228 
3229  if (viewsize==0) {
3230    owl_function_error("No messages present");
3231    return;
3232  }
3233
3234  if (mode==0) {
3235    start=curmsg;
3236  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3237    start=curmsg+1;
3238  } else {
3239    start=curmsg-1;
3240  }
3241
3242  /* bounds check */
3243  if (start>=viewsize || start<0) {
3244    owl_function_error("No further matches found");
3245    return;
3246  }
3247
3248  for (i=start; i<viewsize && i>=0;) {
3249    m=owl_view_get_element(v, i);
3250    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3251      owl_global_set_curmsg(&g, i);
3252      owl_function_calculate_topmsg(direction);
3253      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3254      if (direction==OWL_DIRECTION_DOWNWARDS) {
3255        owl_global_set_direction_downwards(&g);
3256      } else {
3257        owl_global_set_direction_upwards(&g);
3258      }
3259      return;
3260    }
3261    if (direction==OWL_DIRECTION_DOWNWARDS) {
3262      i++;
3263    } else {
3264      i--;
3265    }
3266  }
3267  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3268  owl_function_error("No matches found");
3269}
3270
3271/* strips formatting from ztext and returns the unformatted text.
3272 * caller is responsible for freeing. */
3273char *owl_function_ztext_stylestrip(char *zt)
3274{
3275  owl_fmtext fm;
3276  char *plaintext;
3277
3278  owl_fmtext_init_null(&fm);
3279  owl_fmtext_append_ztext(&fm, zt);
3280  plaintext = owl_fmtext_print_plain(&fm);
3281  owl_fmtext_free(&fm);
3282  return(plaintext);
3283}
3284
3285/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3286void owl_function_buddylist(int aim, int zephyr, char *filename)
3287{
3288  int i, j, x, idle;
3289  owl_fmtext fm;
3290  owl_buddylist *bl;
3291  owl_buddy *b;
3292  owl_list anyone;
3293  char *foo, *timestr;
3294#ifdef HAVE_LIBZEPHYR
3295  char *tmp, *user, *line;
3296  ZLocations_t location[200];
3297  int numlocs, ret;
3298#endif
3299
3300  owl_fmtext_init_null(&fm);
3301
3302  /* AIM first */
3303  if (aim && owl_global_is_aimloggedin(&g)) {
3304    bl=owl_global_get_buddylist(&g);
3305
3306    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3307    /* we're assuming AIM for now */
3308    j=owl_buddylist_get_size(bl);
3309    for (i=0; i<j; i++) {
3310      b=owl_buddylist_get_buddy_n(bl, i);
3311      idle=owl_buddy_get_idle_time(b);
3312      if (idle!=0) {
3313        timestr=owl_util_minutes_to_timestr(idle);
3314      } else {
3315        timestr=owl_strdup("");
3316      }
3317      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3318      owl_fmtext_append_normal(&fm, foo);
3319      owl_free(timestr);
3320      owl_free(foo);
3321    }
3322  }
3323
3324#ifdef HAVE_LIBZEPHYR
3325  if (zephyr) {
3326    if(!owl_global_is_havezephyr(&g)) {
3327      owl_function_error("Zephyr currently not available.");
3328    } else {
3329      owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3330      owl_list_create(&anyone);
3331      ret=owl_zephyr_get_anyone_list(&anyone, filename);
3332      if (ret) {
3333        owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3334      } else {
3335        j=owl_list_get_size(&anyone);
3336        for (i=0; i<j; i++) {
3337          user=owl_list_get_element(&anyone, i);
3338          ret=ZLocateUser(user, &numlocs, ZAUTH);
3339          if (ret!=ZERR_NONE) {
3340            owl_function_error("Error getting location for %s", user);
3341            continue;
3342          }
3343
3344          numlocs=200;
3345          ret=ZGetLocations(location, &numlocs);
3346          if (ret==0) {
3347            for (x=0; x<numlocs; x++) {
3348              line=malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3349              tmp=short_zuser(user);
3350              sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3351                      tmp,
3352                      location[x].host,
3353                      location[x].tty,
3354                      location[x].time);
3355              owl_fmtext_append_normal(&fm, line);
3356              owl_free(tmp);
3357              owl_free(line);
3358            }
3359            if (numlocs>=200) {
3360              owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3361            }
3362          }
3363        }
3364      }
3365      owl_list_free_all(&anyone, owl_free);
3366    } 
3367  }
3368#endif
3369
3370  if(aim && zephyr) {
3371      if(owl_perlconfig_is_function("BarnOwl::Hooks::_get_blist")) {
3372          char * perlblist = owl_perlconfig_execute("BarnOwl::Hooks::_get_blist()");
3373          if(perlblist) {
3374              owl_fmtext_append_ztext(&fm, perlblist);
3375              owl_free(perlblist);
3376          }
3377      }
3378  }
3379 
3380  owl_function_popless_fmtext(&fm);
3381  owl_fmtext_free(&fm);
3382}
3383
3384/* Dump messages in the current view to the file 'filename'. */
3385void owl_function_dump(char *filename) 
3386{
3387  int i, j, count;
3388  owl_message *m;
3389  owl_view *v;
3390  FILE *file;
3391
3392  v=owl_global_get_current_view(&g);
3393
3394  /* in the future make it ask yes/no */
3395  /*
3396  ret=stat(filename, &sbuf);
3397  if (!ret) {
3398    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3399    if (!ret) return;
3400  }
3401  */
3402
3403  file=fopen(filename, "w");
3404  if (!file) {
3405    owl_function_error("Error opening file");
3406    return;
3407  }
3408
3409  count=0;
3410  j=owl_view_get_size(v);
3411  for (i=0; i<j; i++) {
3412    m=owl_view_get_element(v, i);
3413    fputs(owl_message_get_text(m), file);
3414  }
3415  fclose(file);
3416  owl_function_makemsg("Messages dumped to %s", filename);
3417}
3418
3419void owl_function_do_newmsgproc(void)
3420{
3421  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3422    /* if there's a process out there, we need to check on it */
3423    if (owl_global_get_newmsgproc_pid(&g)) {
3424      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3425      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3426      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3427      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3428        /* it exited */
3429        owl_global_set_newmsgproc_pid(&g, 0);
3430        owl_function_debugmsg("newmsgproc exited");
3431      } else {
3432        owl_function_debugmsg("newmsgproc did not exit");
3433      }
3434    }
3435   
3436    /* if it exited, fork & exec a new one */
3437    if (owl_global_get_newmsgproc_pid(&g)==0) {
3438      int i, myargc;
3439      i=fork();
3440      if (i) {
3441        /* parent set the child's pid */
3442        owl_global_set_newmsgproc_pid(&g, i);
3443        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3444      } else {
3445        /* child exec's the program */
3446        char **parsed;
3447        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3448        if (myargc < 0) {
3449          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3450        }
3451        if (myargc <= 0) {
3452          _exit(127);
3453        }
3454        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3455        parsed[myargc] = NULL;
3456       
3457        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3458       
3459        execvp(parsed[0], parsed);
3460       
3461       
3462        /* was there an error exec'ing? */
3463        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3464                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3465        _exit(127);
3466      }
3467    }
3468  }
3469}
3470
3471/* print the xterm escape sequence to raise the window */
3472void owl_function_xterm_raise(void)
3473{
3474  printf("\033[5t");
3475}
3476
3477/* print the xterm escape sequence to deiconify the window */
3478void owl_function_xterm_deiconify(void)
3479{
3480  printf("\033[1t");
3481}
3482
3483/* Add the specified command to the startup file.  Eventually this
3484 * should be clever, and rewriting settings that will obviosly
3485 * override earlier settings with 'set' 'bindkey' and 'alias'
3486 * commands.  For now though we just remove any line that would
3487 * duplicate this one and then append this line to the end of
3488 * startupfile.
3489 */
3490void owl_function_addstartup(char *buff)
3491{
3492  FILE *file;
3493  char *filename;
3494
3495  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3496  file=fopen(filename, "a");
3497  if (!file) {
3498    owl_function_error("Error opening startupfile for new command");
3499    owl_free(filename);
3500    return;
3501  }
3502
3503  /* delete earlier copies */
3504  owl_util_file_deleteline(filename, buff, 1);
3505  owl_free(filename);
3506
3507  /* add this line */
3508  fprintf(file, "%s\n", buff);
3509
3510  fclose(file);
3511}
3512
3513/* Remove the specified command from the startup file. */
3514void owl_function_delstartup(char *buff)
3515{
3516  char *filename;
3517  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3518  owl_util_file_deleteline(filename, buff, 1);
3519  owl_free(filename);
3520}
3521
3522/* Execute owl commands from the given filename.  If the filename
3523 * is NULL, use the default owl startup commands file.
3524 */
3525void owl_function_source(char *filename)
3526{
3527  FILE *file;
3528  char buff[LINE];
3529
3530  if (!filename) {
3531    filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3532    file=fopen(filename, "r");
3533    owl_free(filename);
3534  } else {
3535    file=fopen(filename, "r");
3536  }
3537  if (!file) {
3538    /* just fail silently if it doesn't exist */
3539    return;
3540  }
3541  while (fgets(buff, LINE, file)!=NULL) {
3542    if (buff[0] == '#') continue;
3543    buff[strlen(buff)-1]='\0';
3544    owl_function_command(buff);
3545  }
3546  fclose(file);
3547}
3548
3549void owl_function_change_style(owl_view *v, char *stylename)
3550{
3551  owl_style *s;
3552
3553  s=owl_global_get_style_by_name(&g, stylename);
3554  if (!s) {
3555    owl_function_error("No style named %s", stylename);
3556    return;
3557  }
3558  owl_view_set_style(v, s);
3559  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3560  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3561  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3562}
3563
3564void owl_function_toggleoneline()
3565{
3566  owl_view *v;
3567  owl_style *s;
3568
3569  v=owl_global_get_current_view(&g);
3570  s=owl_view_get_style(v);
3571
3572  if (!owl_style_matches_name(s, "oneline")) {
3573    owl_function_change_style(v, "oneline");
3574  } else {
3575    owl_function_change_style(v, owl_global_get_default_style(&g));
3576  }
3577
3578  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3579  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3580  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3581}
3582
3583void owl_function_error(char *fmt, ...)
3584{
3585  va_list ap;
3586  char buff[2048], buff2[2048];
3587  char *date;
3588  time_t now;
3589
3590  now=time(NULL);
3591  date=owl_strdup(ctime(&now));
3592  date[strlen(date)-1]='\0';
3593
3594  va_start(ap, fmt);
3595
3596  vsnprintf(buff, 2048, fmt, ap);
3597  sprintf(buff2, "%s %s", date, buff);
3598  owl_function_debugmsg("ERROR: %s", buff);
3599  if (owl_global_get_curs_msgwin(&g)) {
3600    werase(owl_global_get_curs_msgwin(&g));
3601    waddstr(owl_global_get_curs_msgwin(&g), buff); 
3602    wnoutrefresh(owl_global_get_curs_msgwin(&g));
3603    owl_global_set_needrefresh(&g);
3604  }
3605  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3606  va_end(ap);
3607  owl_free(date);
3608}
3609
3610void owl_function_showerrs()
3611{
3612  owl_fmtext fm;
3613
3614  owl_fmtext_init_null(&fm);
3615  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3616  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3617  owl_function_popless_fmtext(&fm);
3618}
3619
3620void owl_function_makemsg(char *fmt, ...)
3621{
3622  va_list ap;
3623  char buff[2048];
3624
3625  if (!owl_global_get_curs_msgwin(&g)) return;
3626
3627  va_start(ap, fmt);
3628  werase(owl_global_get_curs_msgwin(&g));
3629 
3630  vsnprintf(buff, 2048, fmt, ap);
3631  owl_function_debugmsg("makemsg: %s", buff);
3632  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3633  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3634  owl_global_set_needrefresh(&g);
3635  va_end(ap);
3636}
3637
3638/* get locations for everyone in .anyone.  If 'notify' is '1' then
3639 * send a pseudo login or logout message for everyone not in sync with
3640 * the global zephyr buddy list.  The list is updated regardless of
3641 * the status of 'notify'.
3642 */
3643void owl_function_zephyr_buddy_check(int notify)
3644{
3645#ifdef HAVE_LIBZEPHYR
3646  int i, j;
3647  owl_list anyone;
3648  owl_message *m;
3649  owl_zbuddylist *zbl;
3650  char *user;
3651  ZLocations_t location[200];
3652  int numlocs, ret;
3653
3654  zbl=owl_global_get_zephyr_buddylist(&g);
3655
3656  owl_list_create(&anyone);
3657  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3658
3659  j=owl_list_get_size(&anyone);
3660  for (i=0; i<j; i++) {
3661    user=owl_list_get_element(&anyone, i);
3662    ret=ZLocateUser(user, &numlocs, ZAUTH);
3663    if (ret!=ZERR_NONE) {
3664      owl_function_error("Error getting location for %s", user);
3665      continue;
3666    }
3667    numlocs=200;
3668    ret=ZGetLocations(location, &numlocs);
3669    if (ret==0) {
3670      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3671        /* Send a PSEUDO LOGIN! */
3672        if (notify) {
3673          m=owl_malloc(sizeof(owl_message));
3674          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3675          owl_global_messagequeue_addmsg(&g, m);
3676        }
3677        owl_zbuddylist_adduser(zbl, user);
3678        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3679      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3680        /* I don't think this ever happens (if there are 0 locations we should get an error from
3681         * ZGetLocations)
3682         */
3683        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3684      }
3685    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3686      /* Send a PSEUDO LOGOUT! */
3687      if (notify) {
3688        m=owl_malloc(sizeof(owl_message));
3689        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3690        owl_global_messagequeue_addmsg(&g, m);
3691      }
3692      owl_zbuddylist_deluser(zbl, user);
3693      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3694    }
3695  }
3696
3697  owl_list_free_all(&anyone, owl_free);
3698#endif
3699}
3700
3701void owl_function_aimsearch_results(char *email, owl_list *namelist)
3702{
3703  owl_fmtext fm;
3704  int i, j;
3705
3706  owl_fmtext_init_null(&fm);
3707  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3708  owl_fmtext_append_normal(&fm, email);
3709  owl_fmtext_append_normal(&fm, ":\n");
3710
3711  j=owl_list_get_size(namelist);
3712  for (i=0; i<j; i++) {
3713    owl_fmtext_append_normal(&fm, "  ");
3714    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3715    owl_fmtext_append_normal(&fm, "\n");
3716  }
3717
3718  owl_function_popless_fmtext(&fm);
3719  owl_fmtext_free(&fm);
3720}
Note: See TracBrowser for help on using the repository browser.