source: functions.c @ 3dcccba

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