source: functions.c @ 4211f50b

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