source: functions.c @ f2fc5ad

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