source: functions.c @ 61abb18

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