source: functions.c @ bfc127b

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