source: functions.c @ fe1f605

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since fe1f605 was fe1f605, checked in by James M. Kretchmar <kretch@mit.edu>, 20 years ago
Catch SIGHUP and SIGTERM and do a proper logout
  • Property mode set to 100644
File size: 94.6 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
2303void owl_function_change_currentview_filter(char *filtname)
2304{
2305  owl_view *v;
2306  owl_filter *f;
2307  int curid=-1, newpos, curmsg;
2308  owl_message *curm=NULL;
2309
2310  v=owl_global_get_current_view(&g);
2311
2312  curmsg=owl_global_get_curmsg(&g);
2313  if (curmsg==-1) {
2314    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2315  } else {
2316    curm=owl_view_get_element(v, curmsg);
2317    if (curm) {
2318      curid=owl_message_get_id(curm);
2319      owl_view_save_curmsgid(v, curid);
2320    }
2321  }
2322
2323  f=owl_global_get_filter(&g, filtname);
2324  if (!f) {
2325    owl_function_error("Unknown filter %s", filtname);
2326    return;
2327  }
2328
2329  owl_view_new_filter(v, f);
2330
2331  /* Figure out what to set the current message to.
2332   * - If the view we're leaving has messages in it, go to the closest message
2333   *   to the last message pointed to in that view.
2334   * - If the view we're leaving is empty, try to restore the position
2335   *   from the last time we were in the new view.  */
2336  if (curm) {
2337    newpos = owl_view_get_nearest_to_msgid(v, curid);
2338  } else {
2339    newpos = owl_view_get_nearest_to_saved(v);
2340  }
2341
2342  owl_global_set_curmsg(&g, newpos);
2343  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2344  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2345  owl_global_set_direction_downwards(&g);
2346}
2347
2348void owl_function_create_filter(int argc, char **argv)
2349{
2350  owl_filter *f;
2351  owl_view *v;
2352  int ret, inuse=0;
2353
2354  if (argc < 2) {
2355    owl_function_error("Wrong number of arguments to filter command");
2356    return;
2357  }
2358
2359  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2360
2361  v=owl_global_get_current_view(&g);
2362
2363  /* don't touch the all filter */
2364  if (!strcmp(argv[1], "all")) {
2365    owl_function_error("You may not change the 'all' filter.");
2366    return;
2367  }
2368
2369  /* deal with the case of trying change the filter color */
2370  if (argc==4 && !strcmp(argv[2], "-c")) {
2371    f=owl_global_get_filter(&g, argv[1]);
2372    if (!f) {
2373      owl_function_error("The filter '%s' does not exist.", argv[1]);
2374      return;
2375    }
2376    if (owl_util_string_to_color(argv[3])==-1) {
2377      owl_function_error("The color '%s' is not available.", argv[3]);
2378      return;
2379    }
2380    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
2381    owl_global_set_needrefresh(&g);
2382    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2383    return;
2384  }
2385
2386  /* create the filter and check for errors */
2387  f=owl_malloc(sizeof(owl_filter));
2388  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2389  if (ret==-1) {
2390    owl_free(f);
2391    owl_function_error("Invalid filter");
2392    return;
2393  }
2394
2395  /* if the named filter is in use by the current view, remember it */
2396  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2397    inuse=1;
2398  }
2399
2400  /* if the named filter already exists, nuke it */
2401  if (owl_global_get_filter(&g, argv[1])) {
2402    owl_global_remove_filter(&g, argv[1]);
2403  }
2404
2405  /* add the filter */
2406  owl_global_add_filter(&g, f);
2407
2408  /* if it was in use by the current view then update */
2409  if (inuse) {
2410    owl_function_change_currentview_filter(argv[1]);
2411  }
2412  owl_global_set_needrefresh(&g);
2413  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2414}
2415
2416/* If 'filtername' does not start with 'not-' create a filter named
2417 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2418 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2419 * 'filtername' begins with 'not-' and a filter 'filtername' already
2420 * exists, then do nothing.  If the filter 'filtername' does not
2421 * exist, create it and define it as 'not filter <filtername>'
2422 *
2423 * Returns the name of the negated filter, which the caller must free.
2424 */
2425char *owl_function_create_negative_filter(char *filtername)
2426{
2427  char *newname;
2428  owl_filter *tmpfilt;
2429  char *argv[5];
2430
2431  owl_function_debugmsg("owl_function_create_negative_filter");
2432 
2433  if (!strncmp(filtername, "not-", 4)) {
2434    newname=owl_strdup(filtername+4);
2435  } else {
2436    newname=owl_sprintf("not-%s", filtername);
2437  }
2438
2439  tmpfilt=owl_global_get_filter(&g, newname);
2440  if (!tmpfilt) {
2441    argv[0]="filter"; /* anything is fine here */
2442    argv[1]=newname;
2443    argv[2]="not";
2444    argv[3]="filter";
2445    argv[4]=filtername;
2446    owl_function_create_filter(5, argv);
2447  }
2448
2449  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2450  return(newname);
2451}
2452
2453void owl_function_show_filters()
2454{
2455  owl_list *l;
2456  owl_filter *f;
2457  int i, j;
2458  owl_fmtext fm;
2459
2460  owl_fmtext_init_null(&fm);
2461
2462  l=owl_global_get_filterlist(&g);
2463  j=owl_list_get_size(l);
2464
2465  owl_fmtext_append_bold(&fm, "Filters:\n");
2466
2467  for (i=0; i<j; i++) {
2468    f=owl_list_get_element(l, i);
2469    owl_fmtext_append_normal(&fm, "   ");
2470    if (owl_global_get_hascolors(&g)) {
2471      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
2472    } else {
2473      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2474    }
2475    owl_fmtext_append_normal(&fm, "\n");
2476  }
2477  owl_function_popless_fmtext(&fm);
2478  owl_fmtext_free(&fm);
2479}
2480
2481void owl_function_show_filter(char *name)
2482{
2483  owl_filter *f;
2484  char buff[5000];
2485
2486  f=owl_global_get_filter(&g, name);
2487  if (!f) {
2488    owl_function_error("There is no filter named %s", name);
2489    return;
2490  }
2491  owl_filter_print(f, buff);
2492  owl_function_popless_text(buff);
2493}
2494
2495void owl_function_show_zpunts()
2496{
2497  owl_filter *f;
2498  owl_list *fl;
2499  char buff[5000];
2500  owl_fmtext fm;
2501  int i, j;
2502
2503  owl_fmtext_init_null(&fm);
2504
2505  fl=owl_global_get_puntlist(&g);
2506  j=owl_list_get_size(fl);
2507  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2508
2509  for (i=0; i<j; i++) {
2510    f=owl_list_get_element(fl, i);
2511    owl_filter_print(f, buff);
2512    owl_fmtext_append_normal(&fm, buff);
2513  }
2514  owl_function_popless_fmtext(&fm);
2515  owl_fmtext_free(&fm);
2516}
2517
2518/* Create a filter for a class, instance if one doesn't exist.  If
2519 * instance is NULL then catch all messgaes in the class.  Returns the
2520 * name of the filter, which the caller must free.
2521 */
2522char *owl_function_classinstfilt(char *class, char *instance) 
2523{
2524  owl_list *fl;
2525  owl_filter *f;
2526  char *argbuff, *filtname;
2527  char *tmpclass, *tmpinstance = NULL;
2528  int len;
2529
2530  fl=owl_global_get_filterlist(&g);
2531
2532  /* name for the filter */
2533  len=strlen(class)+30;
2534  if (instance) len+=strlen(instance);
2535  filtname=owl_malloc(len);
2536  if (!instance) {
2537    sprintf(filtname, "class-%s", class);
2538  } else {
2539    sprintf(filtname, "class-%s-instance-%s", class, instance);
2540  }
2541  /* downcase it */
2542  downstr(filtname);
2543  /* turn spaces into dots */
2544  owl_text_tr(filtname, ' ', '.');
2545 
2546  /* if it already exists then go with it.  This lets users override */
2547  if (owl_global_get_filter(&g, filtname)) {
2548    return(filtname);
2549  }
2550
2551  /* create the new filter */
2552  argbuff=owl_malloc(len+20);
2553  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2554  owl_text_tr(tmpclass, ' ', '.');
2555  if (instance) {
2556    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2557    owl_text_tr(tmpinstance, ' ', '.');
2558  }
2559  sprintf(argbuff, "( class ^%s$ )", tmpclass);
2560  if (tmpinstance) {
2561    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, tmpinstance);
2562  }
2563  owl_free(tmpclass);
2564  if (tmpinstance) owl_free(tmpinstance);
2565
2566  f=owl_malloc(sizeof(owl_filter));
2567  owl_filter_init_fromstring(f, filtname, argbuff);
2568
2569  /* add it to the global list */
2570  owl_global_add_filter(&g, f);
2571
2572  owl_free(argbuff);
2573  return(filtname);
2574}
2575
2576/* Create a filter for personal zephyrs to or from the specified
2577 * zephyr user.  Includes login/logout notifications for the user.
2578 * The name of the filter will be 'user-<user>'.  If a filter already
2579 * exists with this name, no new filter will be created.  This allows
2580 * the configuration to override this function.  Returns the name of
2581 * the filter, which the caller must free.
2582 */
2583char *owl_function_zuserfilt(char *user)
2584{
2585  owl_filter *f;
2586  char *argbuff, *longuser, *shortuser, *filtname;
2587
2588  /* stick the local realm on if it's not there */
2589  longuser=long_zuser(user);
2590  shortuser=short_zuser(user);
2591
2592  /* name for the filter */
2593  filtname=owl_malloc(strlen(shortuser)+20);
2594  sprintf(filtname, "user-%s", shortuser);
2595
2596  /* if it already exists then go with it.  This lets users override */
2597  if (owl_global_get_filter(&g, filtname)) {
2598    return(owl_strdup(filtname));
2599  }
2600
2601  /* create the new-internal filter */
2602  f=owl_malloc(sizeof(owl_filter));
2603
2604  argbuff=owl_malloc(strlen(longuser)+1000);
2605  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2606  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2607  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
2608
2609  owl_filter_init_fromstring(f, filtname, argbuff);
2610
2611  /* add it to the global list */
2612  owl_global_add_filter(&g, f);
2613
2614  /* free stuff */
2615  owl_free(argbuff);
2616  owl_free(longuser);
2617  owl_free(shortuser);
2618
2619  return(filtname);
2620}
2621
2622/* Create a filter for AIM IM messages to or from the specified
2623 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2624 * filter already exists with this name, no new filter will be
2625 * created.  This allows the configuration to override this function.
2626 * Returns the name of the filter, which the caller must free.
2627 */
2628char *owl_function_aimuserfilt(char *user)
2629{
2630  owl_filter *f;
2631  char *argbuff, *filtname;
2632
2633  /* name for the filter */
2634  filtname=owl_malloc(strlen(user)+40);
2635  sprintf(filtname, "aimuser-%s", user);
2636
2637  /* if it already exists then go with it.  This lets users override */
2638  if (owl_global_get_filter(&g, filtname)) {
2639    return(owl_strdup(filtname));
2640  }
2641
2642  /* create the new-internal filter */
2643  f=owl_malloc(sizeof(owl_filter));
2644
2645  argbuff=owl_malloc(1000);
2646  sprintf(argbuff,
2647          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2648          user, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), user);
2649
2650  owl_filter_init_fromstring(f, filtname, argbuff);
2651
2652  /* add it to the global list */
2653  owl_global_add_filter(&g, f);
2654
2655  /* free stuff */
2656  owl_free(argbuff);
2657
2658  return(filtname);
2659}
2660
2661char *owl_function_typefilt(char *type)
2662{
2663  owl_filter *f;
2664  char *argbuff, *filtname;
2665
2666  /* name for the filter */
2667  filtname=owl_sprintf("type-%s", type);
2668
2669  /* if it already exists then go with it.  This lets users override */
2670  if (owl_global_get_filter(&g, filtname)) {
2671    return filtname;
2672  }
2673
2674  /* create the new-internal filter */
2675  f=owl_malloc(sizeof(owl_filter));
2676
2677  argbuff = owl_sprintf("type ^%s$", type);
2678
2679  owl_filter_init_fromstring(f, filtname, argbuff);
2680
2681  /* add it to the global list */
2682  owl_global_add_filter(&g, f);
2683
2684  /* free stuff */
2685  owl_free(argbuff);
2686
2687  return filtname;
2688}
2689
2690/* If flag is 1, marks for deletion.  If flag is 0,
2691 * unmarks for deletion. */
2692void owl_function_delete_curview_msgs(int flag)
2693{
2694  owl_view *v;
2695  int i, j;
2696
2697  v=owl_global_get_current_view(&g);
2698  j=owl_view_get_size(v);
2699  for (i=0; i<j; i++) {
2700    if (flag == 1) {
2701      owl_message_mark_delete(owl_view_get_element(v, i));
2702    } else if (flag == 0) {
2703      owl_message_unmark_delete(owl_view_get_element(v, i));
2704    }
2705  }
2706
2707  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2708
2709  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2710}
2711
2712/* Create a filter based on the current message.  Returns the name of
2713 * a filter or null.  The caller must free this name.
2714 *
2715 * if the curmsg is a personal zephyr return a filter name
2716 *    to the zephyr converstaion with that user.
2717 * If the curmsg is a zephyr class message, instance foo, recip *,
2718 *    return a filter name to the class, inst.
2719 * If the curmsg is a zephyr class message and type==0 then
2720 *    return a filter name for just the class.
2721 * If the curmsg is a zephyr class message and type==1 then
2722 *    return a filter name for the class and instance.
2723 * If the curmsg is a personal AIM message returna  filter
2724 *    name to the AIM conversation with that user
2725 */
2726char *owl_function_smartfilter(int type)
2727{
2728  owl_view *v;
2729  owl_message *m;
2730  char *zperson, *filtname=NULL;
2731 
2732  v=owl_global_get_current_view(&g);
2733  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2734
2735  if (!m || owl_view_get_size(v)==0) {
2736    owl_function_error("No message selected\n");
2737    return(NULL);
2738  }
2739
2740  /* very simple handling of admin messages for now */
2741  if (owl_message_is_type_admin(m)) {
2742    return(owl_function_typefilt("admin"));
2743  }
2744
2745  /* very simple handling of loopback messages for now */
2746  if (owl_message_is_type_loopback(m)) {
2747    return(owl_function_typefilt("loopback"));
2748  }
2749
2750  /* aim messages */
2751  if (owl_message_is_type_aim(m)) {
2752    if (owl_message_is_direction_in(m)) {
2753      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2754    } else if (owl_message_is_direction_out(m)) {
2755      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2756    }
2757    return(filtname);
2758  }
2759
2760  /* narrow personal and login messages to the sender or recip as appropriate */
2761  if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2762    if (owl_message_is_type_zephyr(m)) {
2763      if (owl_message_is_direction_in(m)) {
2764        zperson=short_zuser(owl_message_get_sender(m));
2765      } else {
2766        zperson=short_zuser(owl_message_get_recipient(m));
2767      }
2768      filtname=owl_function_zuserfilt(zperson);
2769      owl_free(zperson);
2770      return(filtname);
2771    }
2772    return(NULL);
2773  }
2774
2775  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2776  if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2777    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2778    return(filtname);
2779  }
2780
2781  /* otherwise narrow to the class */
2782  if (type==0) {
2783    filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2784  } else if (type==1) {
2785    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2786  }
2787  return(filtname);
2788}
2789
2790void owl_function_smartzpunt(int type)
2791{
2792  /* Starts a zpunt command based on the current class,instance pair.
2793   * If type=0, uses just class.  If type=1, uses instance as well. */
2794  owl_view *v;
2795  owl_message *m;
2796  char *cmd, *cmdprefix, *mclass, *minst;
2797 
2798  v=owl_global_get_current_view(&g);
2799  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2800
2801  if (!m || owl_view_get_size(v)==0) {
2802    owl_function_error("No message selected\n");
2803    return;
2804  }
2805
2806  /* for now we skip admin messages. */
2807  if (owl_message_is_type_admin(m)
2808      || owl_message_is_loginout(m)
2809      || !owl_message_is_type_zephyr(m)) {
2810    owl_function_error("smartzpunt doesn't support this message type.");
2811    return;
2812  }
2813
2814  mclass = owl_message_get_class(m);
2815  minst = owl_message_get_instance(m);
2816  if (!mclass || !*mclass || *mclass==' '
2817      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2818      || (type && (!minst || !*minst|| *minst==' '))) {
2819    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2820                         mclass, minst);
2821  } else {
2822    cmdprefix = "start-command zpunt ";
2823    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2824    strcpy(cmd, cmdprefix);
2825    strcat(cmd, owl_getquoting(mclass));
2826    strcat(cmd, mclass);
2827    strcat(cmd, owl_getquoting(mclass));
2828    if (type) {
2829      strcat(cmd, " ");
2830      strcat(cmd, owl_getquoting(minst));
2831      strcat(cmd, minst);
2832      strcat(cmd, owl_getquoting(minst));
2833    } else {
2834      strcat(cmd, " *");
2835    }
2836    owl_function_command(cmd);
2837    owl_free(cmd);
2838  }
2839}
2840
2841void owl_function_color_current_filter(char *color)
2842{
2843  owl_filter *f;
2844  char *name;
2845
2846  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2847  f=owl_global_get_filter(&g, name);
2848  if (!f) {
2849    owl_function_error("Unknown filter");
2850    return;
2851  }
2852
2853  /* don't touch the all filter */
2854  if (!strcmp(name, "all")) {
2855    owl_function_error("You may not change the 'all' filter.");
2856    return;
2857  }
2858
2859  /* deal with the case of trying change the filter color */
2860  if (owl_util_string_to_color(color)==-1) {
2861    owl_function_error("No color named '%s' avilable.");
2862    return;
2863  }
2864  owl_filter_set_color(f, owl_util_string_to_color(color));
2865  owl_global_set_needrefresh(&g);
2866  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2867}
2868
2869void owl_function_show_colors()
2870{
2871  owl_fmtext fm;
2872
2873  owl_fmtext_init_null(&fm);
2874  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2875  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2876  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2877  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2878  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2879  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2880  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2881  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2882
2883  owl_function_popless_fmtext(&fm);
2884  owl_fmtext_free(&fm);
2885}
2886
2887/* add the given class, inst, recip to the punt list for filtering.
2888 *   if direction==0 then punt
2889 *   if direction==1 then unpunt
2890 */
2891void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2892{
2893  owl_filter *f;
2894  owl_list *fl;
2895  char *buff;
2896  char *quoted;
2897  int ret, i, j;
2898
2899  fl=owl_global_get_puntlist(&g);
2900
2901  /* first, create the filter */
2902  f=malloc(sizeof(owl_filter));
2903  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2904  strcpy(buff, "class");
2905  if (!strcmp(class, "*")) {
2906    strcat(buff, " .*");
2907  } else {
2908    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2909    owl_text_tr(quoted, ' ', '.');
2910    sprintf(buff, "%s ^%s$", buff, quoted);
2911    owl_free(quoted);
2912  }
2913  if (!strcmp(inst, "*")) {
2914    strcat(buff, " and instance .*");
2915  } else {
2916    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2917    owl_text_tr(quoted, ' ', '.');
2918    sprintf(buff, "%s and instance ^%s$", buff, quoted);
2919    owl_free(quoted);
2920  }
2921  if (strcmp(recip, "*")) {
2922    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2923    owl_text_tr(quoted, ' ', '.');
2924    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
2925    owl_free(quoted);
2926  }
2927 
2928  owl_function_debugmsg("About to filter %s", buff);
2929  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2930  owl_free(buff);
2931  if (ret) {
2932    owl_function_error("Error creating filter for zpunt");
2933    owl_filter_free(f);
2934    return;
2935  }
2936
2937  /* Check for an identical filter */
2938  j=owl_list_get_size(fl);
2939  for (i=0; i<j; i++) {
2940    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2941      /* if we're punting, then just silently bow out on this duplicate */
2942      if (direction==0) {
2943        owl_filter_free(f);
2944        return;
2945      }
2946
2947      /* if we're unpunting, then remove this filter from the puntlist */
2948      if (direction==1) {
2949        owl_filter_free(owl_list_get_element(fl, i));
2950        owl_list_remove_element(fl, i);
2951        return;
2952      }
2953    }
2954  }
2955
2956  /* If we're punting, add the filter to the global punt list */
2957  if (direction==0) {
2958    owl_list_append_element(fl, f);
2959  }
2960}
2961
2962void owl_function_activate_keymap(char *keymap)
2963{
2964  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2965    owl_function_error("Unable to activate keymap '%s'", keymap);
2966  }
2967}
2968
2969void owl_function_show_keymaps()
2970{
2971  owl_list l;
2972  owl_fmtext fm;
2973  owl_keymap *km;
2974  owl_keyhandler *kh;
2975  int i, numkm;
2976  char *kmname;
2977
2978  kh = owl_global_get_keyhandler(&g);
2979  owl_fmtext_init_null(&fm);
2980  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2981  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2982  owl_keyhandler_get_keymap_names(kh, &l);
2983  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2984  owl_fmtext_append_normal(&fm, "\n");
2985
2986  numkm = owl_list_get_size(&l);
2987  for (i=0; i<numkm; i++) {
2988    kmname = owl_list_get_element(&l, i);
2989    km = owl_keyhandler_get_keymap(kh, kmname);
2990    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2991    owl_keymap_get_details(km, &fm);   
2992  }
2993  owl_fmtext_append_normal(&fm, "\n");
2994 
2995  owl_function_popless_fmtext(&fm);
2996  owl_keyhandler_keymap_namelist_free(&l);
2997  owl_fmtext_free(&fm);
2998}
2999
3000char *owl_function_keymap_summary(void *name)
3001{
3002  owl_keymap *km
3003    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3004  if (km) return owl_keymap_summary(km);
3005  else return(NULL);
3006}
3007
3008/* TODO: implement for real */
3009void owl_function_show_keymap(char *name)
3010{
3011  owl_fmtext fm;
3012  owl_keymap *km;
3013
3014  owl_fmtext_init_null(&fm);
3015  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3016  if (km) {
3017    owl_keymap_get_details(km, &fm);
3018  } else {
3019    owl_fmtext_append_normal(&fm, "No such keymap...\n");
3020  } 
3021  owl_function_popless_fmtext(&fm);
3022  owl_fmtext_free(&fm);
3023}
3024
3025void owl_function_help_for_command(char *cmdname)
3026{
3027  owl_fmtext fm;
3028
3029  owl_fmtext_init_null(&fm);
3030  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3031  owl_function_popless_fmtext(&fm); 
3032  owl_fmtext_free(&fm);
3033}
3034
3035void owl_function_search_start(char *string, int direction)
3036{
3037  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3038  owl_global_set_search_active(&g, string);
3039  owl_function_search_helper(0, direction);
3040}
3041
3042void owl_function_search_continue(int direction)
3043{
3044  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3045  owl_function_search_helper(1, direction);
3046}
3047
3048void owl_function_search_helper(int mode, int direction)
3049{
3050  /* move to a message that contains the string.  If direction is
3051   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3052   * OWL_DIRECTION_UPWARDS then search backwards.
3053   *
3054   * If mode==0 then it will stay on the current message if it
3055   * contains the string.
3056   */
3057
3058  owl_view *v;
3059  int viewsize, i, curmsg, start;
3060  owl_message *m;
3061
3062  v=owl_global_get_current_view(&g);
3063  viewsize=owl_view_get_size(v);
3064  curmsg=owl_global_get_curmsg(&g);
3065 
3066  if (viewsize==0) {
3067    owl_function_error("No messages present");
3068    return;
3069  }
3070
3071  if (mode==0) {
3072    start=curmsg;
3073  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3074    start=curmsg+1;
3075  } else {
3076    start=curmsg-1;
3077  }
3078
3079  /* bounds check */
3080  if (start>=viewsize || start<0) {
3081    owl_function_error("No further matches found");
3082    return;
3083  }
3084
3085  for (i=start; i<viewsize && i>=0;) {
3086    m=owl_view_get_element(v, i);
3087    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3088      owl_global_set_curmsg(&g, i);
3089      owl_function_calculate_topmsg(direction);
3090      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3091      if (direction==OWL_DIRECTION_DOWNWARDS) {
3092        owl_global_set_direction_downwards(&g);
3093      } else {
3094        owl_global_set_direction_upwards(&g);
3095      }
3096      return;
3097    }
3098    if (direction==OWL_DIRECTION_DOWNWARDS) {
3099      i++;
3100    } else {
3101      i--;
3102    }
3103  }
3104  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3105  owl_function_error("No matches found");
3106}
3107
3108/* strips formatting from ztext and returns the unformatted text.
3109 * caller is responsible for freeing. */
3110char *owl_function_ztext_stylestrip(char *zt)
3111{
3112  owl_fmtext fm;
3113  char *plaintext;
3114
3115  owl_fmtext_init_null(&fm);
3116  owl_fmtext_append_ztext(&fm, zt);
3117  plaintext = owl_fmtext_print_plain(&fm);
3118  owl_fmtext_free(&fm);
3119  return(plaintext);
3120}
3121
3122/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3123void owl_function_buddylist(int aim, int zephyr, char *filename)
3124{
3125  int i, j, x, idle;
3126  owl_fmtext fm;
3127  owl_buddylist *bl;
3128  owl_buddy *b;
3129  owl_list anyone;
3130  char *foo, *timestr;
3131#ifdef HAVE_LIBZEPHYR
3132  char *tmp, *user, *line;
3133  ZLocations_t location[200];
3134  int numlocs, ret;
3135#endif
3136
3137  owl_fmtext_init_null(&fm);
3138
3139  /* AIM first */
3140  if (aim && owl_global_is_aimloggedin(&g)) {
3141    bl=owl_global_get_buddylist(&g);
3142
3143    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3144    /* we're assuming AIM for now */
3145    j=owl_buddylist_get_size(bl);
3146    for (i=0; i<j; i++) {
3147      b=owl_buddylist_get_buddy_n(bl, i);
3148      idle=owl_buddy_get_idle_time(b);
3149      if (idle!=0) {
3150        timestr=owl_util_minutes_to_timestr(idle);
3151      } else {
3152        timestr=owl_strdup("");
3153      }
3154      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3155      owl_fmtext_append_normal(&fm, foo);
3156      owl_free(timestr);
3157      owl_free(foo);
3158    }
3159  }
3160
3161#ifdef HAVE_LIBZEPHYR
3162  if (zephyr) {
3163    owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3164    owl_list_create(&anyone);
3165    ret=owl_zephyr_get_anyone_list(&anyone, filename);
3166    if (ret) {
3167      owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3168    } else {
3169      j=owl_list_get_size(&anyone);
3170      for (i=0; i<j; i++) {
3171        user=owl_list_get_element(&anyone, i);
3172        ret=ZLocateUser(user, &numlocs, ZAUTH);
3173        if (ret!=ZERR_NONE) {
3174          owl_function_error("Error getting location for %s", user);
3175          continue;
3176        }
3177       
3178        numlocs=200;
3179        ret=ZGetLocations(location, &numlocs);
3180        if (ret==0) {
3181          for (x=0; x<numlocs; x++) {
3182            line=malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3183            tmp=short_zuser(user);
3184            sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3185                    tmp,
3186                    location[x].host,
3187                    location[x].tty,
3188                    location[x].time);
3189            owl_fmtext_append_normal(&fm, line);
3190            owl_free(tmp);
3191          }
3192          if (numlocs>=200) {
3193            owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3194          }
3195        }
3196      }
3197    }
3198    owl_list_free_all(&anyone, owl_free);
3199  }
3200#endif
3201 
3202  owl_function_popless_fmtext(&fm);
3203  owl_fmtext_free(&fm);
3204}
3205
3206/* Dump messages in the current view to the file 'filename'. */
3207void owl_function_dump(char *filename) 
3208{
3209  int i, j, count;
3210  owl_message *m;
3211  owl_view *v;
3212  FILE *file;
3213
3214  v=owl_global_get_current_view(&g);
3215
3216  /* in the future make it ask yes/no */
3217  /*
3218  ret=stat(filename, &sbuf);
3219  if (!ret) {
3220    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3221    if (!ret) return;
3222  }
3223  */
3224
3225  file=fopen(filename, "w");
3226  if (!file) {
3227    owl_function_error("Error opening file");
3228    return;
3229  }
3230
3231  count=0;
3232  j=owl_view_get_size(v);
3233  for (i=0; i<j; i++) {
3234    m=owl_view_get_element(v, i);
3235    fputs(owl_message_get_text(m), file);
3236  }
3237  fclose(file);
3238  owl_function_makemsg("Messages dumped to %s", filename);
3239}
3240
3241void owl_function_do_newmsgproc(void)
3242{
3243  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3244    /* if there's a process out there, we need to check on it */
3245    if (owl_global_get_newmsgproc_pid(&g)) {
3246      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3247      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3248      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3249      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3250        /* it exited */
3251        owl_global_set_newmsgproc_pid(&g, 0);
3252        owl_function_debugmsg("newmsgproc exited");
3253      } else {
3254        owl_function_debugmsg("newmsgproc did not exit");
3255      }
3256    }
3257   
3258    /* if it exited, fork & exec a new one */
3259    if (owl_global_get_newmsgproc_pid(&g)==0) {
3260      int i, myargc;
3261      i=fork();
3262      if (i) {
3263        /* parent set the child's pid */
3264        owl_global_set_newmsgproc_pid(&g, i);
3265        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3266      } else {
3267        /* child exec's the program */
3268        char **parsed;
3269        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3270        if (myargc < 0) {
3271          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3272        }
3273        if (myargc <= 0) {
3274          _exit(127);
3275        }
3276        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3277        parsed[myargc] = NULL;
3278       
3279        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3280       
3281        execvp(parsed[0], parsed);
3282       
3283       
3284        /* was there an error exec'ing? */
3285        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3286                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3287        _exit(127);
3288      }
3289    }
3290  }
3291}
3292
3293/* print the xterm escape sequence to raise the window */
3294void owl_function_xterm_raise(void)
3295{
3296  printf("\033[5t");
3297}
3298
3299/* print the xterm escape sequence to deiconify the window */
3300void owl_function_xterm_deiconify(void)
3301{
3302  printf("\033[1t");
3303}
3304
3305/* Add the specified command to the startup file.  Eventually this
3306 * should be clever, and rewriting settings that will obviosly
3307 * override earlier settings with 'set' 'bindkey' and 'alias'
3308 * commands.  For now though we just remove any line that would
3309 * duplicate this one and then append this line to the end of
3310 * startupfile.
3311 */
3312void owl_function_addstartup(char *buff)
3313{
3314  FILE *file;
3315  char *filename;
3316
3317  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3318  file=fopen(filename, "a");
3319  if (!file) {
3320    owl_function_error("Error opening startupfile for new command");
3321    owl_free(filename);
3322    return;
3323  }
3324
3325  /* delete earlier copies */
3326  owl_util_file_deleteline(filename, buff, 1);
3327  owl_free(filename);
3328
3329  /* add this line */
3330  fprintf(file, "%s\n", buff);
3331
3332  fclose(file);
3333}
3334
3335/* Remove the specified command from the startup file. */
3336void owl_function_delstartup(char *buff)
3337{
3338  char *filename;
3339  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3340  owl_util_file_deleteline(filename, buff, 1);
3341  owl_free(filename);
3342}
3343
3344/* Execute owl commands from the given filename.  If the filename
3345 * is NULL, use the default owl startup commands file.
3346 */
3347void owl_function_source(char *filename)
3348{
3349  FILE *file;
3350  char buff[LINE];
3351
3352  if (!filename) {
3353    filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3354    file=fopen(filename, "r");
3355    owl_free(filename);
3356  } else {
3357    file=fopen(filename, "r");
3358  }
3359  if (!file) {
3360    /* just fail silently if it doesn't exist */
3361    return;
3362  }
3363  while (fgets(buff, LINE, file)!=NULL) {
3364    buff[strlen(buff)-1]='\0';
3365    owl_function_command(buff);
3366  }
3367  fclose(file);
3368}
3369
3370void owl_function_change_style(owl_view *v, char *stylename)
3371{
3372  owl_style *s;
3373
3374  s=owl_global_get_style_by_name(&g, stylename);
3375  if (!s) {
3376    owl_function_error("No style named %s", stylename);
3377    return;
3378  }
3379  owl_view_set_style(v, s);
3380  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3381  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3382  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3383}
3384
3385void owl_function_toggleoneline()
3386{
3387  owl_view *v;
3388  owl_style *s;
3389
3390  v=owl_global_get_current_view(&g);
3391  s=owl_view_get_style(v);
3392
3393  if (!owl_style_matches_name(s, "oneline")) {
3394    owl_function_change_style(v, "oneline");
3395  } else {
3396    owl_function_change_style(v, owl_global_get_default_style(&g));
3397  }
3398
3399  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3400  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3401  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3402}
3403
3404void owl_function_error(char *fmt, ...)
3405{
3406  va_list ap;
3407  char buff[2048], buff2[2048];
3408  char *date;
3409  time_t now;
3410
3411  now=time(NULL);
3412  date=owl_strdup(ctime(&now));
3413  date[strlen(date)-1]='\0';
3414
3415  va_start(ap, fmt);
3416
3417  vsnprintf(buff, 2048, fmt, ap);
3418  sprintf(buff2, "%s %s", date, buff);
3419  owl_function_debugmsg("ERROR: %s", buff);
3420  if (owl_global_get_curs_msgwin(&g)) {
3421    werase(owl_global_get_curs_msgwin(&g));
3422    waddstr(owl_global_get_curs_msgwin(&g), buff); 
3423    wnoutrefresh(owl_global_get_curs_msgwin(&g));
3424    owl_global_set_needrefresh(&g);
3425  }
3426  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3427  va_end(ap);
3428  owl_free(date);
3429}
3430
3431void owl_function_showerrs()
3432{
3433  owl_fmtext fm;
3434
3435  owl_fmtext_init_null(&fm);
3436  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3437  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3438  owl_function_popless_fmtext(&fm);
3439}
3440
3441void owl_function_makemsg(char *fmt, ...)
3442{
3443  va_list ap;
3444  char buff[2048];
3445
3446  if (!owl_global_get_curs_msgwin(&g)) return;
3447
3448  va_start(ap, fmt);
3449  werase(owl_global_get_curs_msgwin(&g));
3450 
3451  vsnprintf(buff, 2048, fmt, ap);
3452  owl_function_debugmsg("makemsg: %s", buff);
3453  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3454  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3455  owl_global_set_needrefresh(&g);
3456  va_end(ap);
3457}
3458
3459/* get locations for everyone in .anyone.  If 'notify' is '1' then
3460 * send a pseudo login or logout message for everyone not in sync with
3461 * the global zephyr buddy list.  The list is updated regardless of
3462 * the status of 'notify'.
3463 */
3464void owl_function_zephyr_buddy_check(int notify)
3465{
3466#ifdef HAVE_LIBZEPHYR
3467  int i, j;
3468  owl_list anyone;
3469  owl_message *m;
3470  owl_zbuddylist *zbl;
3471  char *user;
3472  ZLocations_t location[200];
3473  int numlocs, ret;
3474
3475  zbl=owl_global_get_zephyr_buddylist(&g);
3476
3477  owl_list_create(&anyone);
3478  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3479
3480  j=owl_list_get_size(&anyone);
3481  for (i=0; i<j; i++) {
3482    user=owl_list_get_element(&anyone, i);
3483    ret=ZLocateUser(user, &numlocs, ZAUTH);
3484    if (ret!=ZERR_NONE) {
3485      owl_function_error("Error getting location for %s", user);
3486      continue;
3487    }
3488    numlocs=200;
3489    ret=ZGetLocations(location, &numlocs);
3490    if (ret==0) {
3491      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3492        /* Send a PSEUDO LOGIN! */
3493        if (notify) {
3494          m=owl_malloc(sizeof(owl_message));
3495          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3496          owl_global_messagequeue_addmsg(&g, m);
3497        }
3498        owl_zbuddylist_adduser(zbl, user);
3499        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3500      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3501        /* I don't think this ever happens (if there are 0 locations we should get an error from
3502         * ZGetLocations)
3503         */
3504        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3505      }
3506    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3507      /* Send a PSEUDO LOGOUT! */
3508      if (notify) {
3509        m=owl_malloc(sizeof(owl_message));
3510        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3511        owl_global_messagequeue_addmsg(&g, m);
3512      }
3513      owl_zbuddylist_deluser(zbl, user);
3514      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3515    }
3516  }
3517
3518  owl_list_free_all(&anyone, owl_free);
3519#endif
3520}
3521
3522void owl_function_aimsearch_results(char *email, owl_list *namelist)
3523{
3524  owl_fmtext fm;
3525  int i, j;
3526
3527  owl_fmtext_init_null(&fm);
3528  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3529  owl_fmtext_append_normal(&fm, email);
3530  owl_fmtext_append_normal(&fm, ":\n");
3531
3532  j=owl_list_get_size(namelist);
3533  for (i=0; i<j; i++) {
3534    owl_fmtext_append_normal(&fm, "  ");
3535    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3536    owl_fmtext_append_normal(&fm, "\n");
3537  }
3538
3539  owl_function_popless_fmtext(&fm);
3540  owl_fmtext_free(&fm);
3541}
Note: See TracBrowser for help on using the repository browser.