source: functions.c @ 5e0b690

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