source: functions.c @ afbf668

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since afbf668 was afbf668, checked in by Erik Nygren <nygren@mit.edu>, 17 years ago
pexec will now incrimentally display data as it is output by the child process. Additionally, commands running under pexec may now be killed by quitting out of the popless window. Added muxevents select loop dispatcher. File descriptors may be registered with muxevents and handlers will be dispatched to when data is available for non-blocking read/write/except. Switched the stderr_redir stuff to use muxevents.
  • 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 
968  /* Quit AIM */
969  if (owl_global_is_aimloggedin(&g)) {
970    owl_aim_logout();
971  }
972
973  /* final clean up */
974  endwin();
975  owl_function_debugmsg("Quitting Owl");
976  exit(0);
977}
978
979void owl_function_openurl()
980{
981  /* visit the first url in the current message */
982  owl_message *m;
983  owl_view *v;
984  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
985  int webbrowser;
986
987  webbrowser = owl_global_get_webbrowser(&g);
988
989  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
990    owl_function_error("No browser selected");
991    return;
992  }
993
994  v=owl_global_get_current_view(&g);
995 
996  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
997
998  if (!m || owl_view_get_size(v)==0) {
999    owl_function_error("No current message selected");
1000    return;
1001  }
1002
1003  text=owl_message_get_text(m);
1004
1005  /* First look for a good URL */ 
1006  if ((ptr1=strstr(text, "http://"))!=NULL) {
1007    ptr2=strpbrk(ptr1, " \n\t");
1008    if (ptr2) {
1009      strncpy(url, ptr1, ptr2-ptr1+1);
1010      url[ptr2-ptr1+1]='\0';
1011    } else {
1012      strcpy(url, ptr1);
1013    }
1014
1015    /* if we had <http strip a trailing > */
1016    if (ptr1>text && ptr1[-1]=='<') {
1017      if (url[strlen(url)-1]=='>') {
1018        url[strlen(url)-1]='\0';
1019      }
1020    }
1021  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
1022    /* Look for an https URL */ 
1023    ptr2=strpbrk(ptr1, " \n\t");
1024    if (ptr2) {
1025      strncpy(url, ptr1, ptr2-ptr1+1);
1026      url[ptr2-ptr1+1]='\0';
1027    } else {
1028      strcpy(url, ptr1);
1029    }
1030   
1031    /* if we had <http strip a trailing > */
1032    if (ptr1>text && ptr1[-1]=='<') {
1033      if (url[strlen(url)-1]=='>') {
1034        url[strlen(url)-1]='\0';
1035      }
1036    }
1037  } else if ((ptr1=strstr(text, "www."))!=NULL) {
1038    /* if we can't find a real url look for www.something */
1039    ptr2=strpbrk(ptr1, " \n\t");
1040    if (ptr2) {
1041      strncpy(url, ptr1, ptr2-ptr1+1);
1042      url[ptr2-ptr1+1]='\0';
1043    } else {
1044      strcpy(url, ptr1);
1045    }
1046  } else {
1047    owl_function_beep();
1048    owl_function_error("Could not find URL to open.");
1049    return;
1050  }
1051
1052  /* Make sure there aren't any quotes or \'s in the url */
1053  for (ptr1 = url; *ptr1; ptr1++) {
1054    if (*ptr1 == '"' || *ptr1 == '\\') {
1055      owl_function_beep();
1056      owl_function_error("URL contains invalid characters.");
1057      return;
1058    }
1059  }
1060 
1061  /* NOTE: There are potentially serious security issues here... */
1062
1063  /* open the page */
1064  owl_function_makemsg("Opening %s", url);
1065  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
1066    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
1067    system(tmpbuff); 
1068  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
1069    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
1070    system(tmpbuff); 
1071  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
1072    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
1073    system(tmpbuff); 
1074  }
1075}
1076
1077void owl_function_calculate_topmsg(int direction)
1078{
1079  int recwinlines, topmsg, curmsg;
1080  owl_view *v;
1081
1082  v=owl_global_get_current_view(&g);
1083  curmsg=owl_global_get_curmsg(&g);
1084  topmsg=owl_global_get_topmsg(&g);
1085  recwinlines=owl_global_get_recwin_lines(&g);
1086
1087  /*
1088  if (owl_view_get_size(v) < 1) {
1089    return;
1090  }
1091  */
1092
1093  switch (owl_global_get_scrollmode(&g)) {
1094  case OWL_SCROLLMODE_TOP:
1095    topmsg = owl_function_calculate_topmsg_top(direction, v, curmsg, topmsg, recwinlines);
1096    break;
1097  case OWL_SCROLLMODE_NEARTOP:
1098    topmsg = owl_function_calculate_topmsg_neartop(direction, v, curmsg, topmsg, recwinlines);
1099    break;
1100  case OWL_SCROLLMODE_CENTER:
1101    topmsg = owl_function_calculate_topmsg_center(direction, v, curmsg, topmsg, recwinlines);
1102    break;
1103  case OWL_SCROLLMODE_PAGED:
1104    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 0);
1105    break;
1106  case OWL_SCROLLMODE_PAGEDCENTER:
1107    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 1);
1108    break;
1109  case OWL_SCROLLMODE_NORMAL:
1110  default:
1111    topmsg = owl_function_calculate_topmsg_normal(direction, v, curmsg, topmsg, recwinlines);
1112  }
1113  owl_function_debugmsg("Calculated a topmsg of %i", topmsg);
1114  owl_global_set_topmsg(&g, topmsg);
1115}
1116
1117/* Returns what the new topmsg should be. 
1118 * Passed the last direction of movement,
1119 * the current view,
1120 * the current message number in the view,
1121 * the top message currently being displayed,
1122 * and the number of lines in the recwin.
1123 */
1124int owl_function_calculate_topmsg_top(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1125{
1126  return(curmsg);
1127}
1128
1129int owl_function_calculate_topmsg_neartop(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1130{
1131  if (curmsg>0 
1132      && (owl_message_get_numlines(owl_view_get_element(v, curmsg-1))
1133          <  recwinlines/2)) {
1134    return(curmsg-1);
1135  } else {
1136    return(curmsg);
1137  }
1138}
1139 
1140int owl_function_calculate_topmsg_center(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1141{
1142  int i, last, lines;
1143
1144  last = curmsg;
1145  lines = 0;
1146  for (i=curmsg-1; i>=0; i--) {
1147    lines += owl_message_get_numlines(owl_view_get_element(v, i));
1148    if (lines > recwinlines/2) break;
1149    last = i;
1150  }
1151  return(last);
1152}
1153 
1154int owl_function_calculate_topmsg_paged(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines, int center_on_page)
1155{
1156  int i, last, lines, savey;
1157 
1158  /* If we're off the top of the screen, scroll up such that the
1159   * curmsg is near the botton of the screen. */
1160  if (curmsg < topmsg) {
1161    last = curmsg;
1162    lines = 0;
1163    for (i=curmsg; i>=0; i--) {
1164      lines += owl_message_get_numlines(owl_view_get_element(v, i));
1165      if (lines > recwinlines) break;
1166    last = i;
1167    }
1168    if (center_on_page) {
1169      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1170    } else {
1171      return(last);
1172    }
1173  }
1174
1175  /* Find number of lines from top to bottom of curmsg (store in savey) */
1176  savey=0;
1177  for (i=topmsg; i<=curmsg; i++) {
1178    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1179  }
1180
1181  /* if we're off the bottom of the screen, scroll down */
1182  if (savey > recwinlines) {
1183    if (center_on_page) {
1184      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1185    } else {
1186      return(curmsg);
1187    }
1188  }
1189
1190  /* else just stay as we are... */
1191  return(topmsg);
1192}
1193
1194int owl_function_calculate_topmsg_normal(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1195{
1196  int savey, j, i, foo, y;
1197
1198  if (curmsg<0) return(topmsg);
1199   
1200  /* If we're off the top of the screen then center */
1201  if (curmsg<topmsg) {
1202    topmsg=owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
1203  }
1204
1205  /* Find number of lines from top to bottom of curmsg (store in savey) */
1206  savey=0;
1207  for (i=topmsg; i<=curmsg; i++) {
1208    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1209  }
1210
1211  /* If we're off the bottom of the screen, set the topmsg to curmsg
1212   * and scroll upwards */
1213  if (savey > recwinlines) {
1214    topmsg=curmsg;
1215    savey=owl_message_get_numlines(owl_view_get_element(v, i));
1216    direction=OWL_DIRECTION_UPWARDS;
1217  }
1218 
1219  /* If our bottom line is less than 1/4 down the screen then scroll up */
1220  if (direction == OWL_DIRECTION_UPWARDS || direction == OWL_DIRECTION_NONE) {
1221    if (savey < (recwinlines / 4)) {
1222      y=0;
1223      for (j=curmsg; j>=0; j--) {
1224        foo=owl_message_get_numlines(owl_view_get_element(v, j));
1225        /* will we run the curmsg off the screen? */
1226        if ((foo+y) >= recwinlines) {
1227          j++;
1228          if (j>curmsg) j=curmsg;
1229          break;
1230        }
1231        /* have saved 1/2 the screen space? */
1232        y+=foo;
1233        if (y > (recwinlines / 2)) break;
1234      }
1235      if (j<0) j=0;
1236      return(j);
1237    }
1238  }
1239
1240  if (direction == OWL_DIRECTION_DOWNWARDS || direction == OWL_DIRECTION_NONE) {
1241    /* If curmsg bottom line is more than 3/4 down the screen then scroll down */
1242    if (savey > ((recwinlines * 3)/4)) {
1243      y=0;
1244      /* count lines from the top until we can save 1/2 the screen size */
1245      for (j=topmsg; j<curmsg; j++) {
1246        y+=owl_message_get_numlines(owl_view_get_element(v, j));
1247        if (y > (recwinlines / 2)) break;
1248      }
1249      if (j==curmsg) {
1250        j--;
1251      }
1252      return(j+1);
1253    }
1254  }
1255
1256  return(topmsg);
1257}
1258
1259void owl_function_resize()
1260{
1261  owl_global_set_resize_pending(&g);
1262}
1263
1264void owl_function_run_buffercommand()
1265{
1266  char *buff, *ptr;
1267
1268  buff=owl_global_get_buffercommand(&g);
1269  if (!strncmp(buff, "zwrite ", 7)) {
1270    owl_function_zwrite(buff, owl_editwin_get_text(owl_global_get_typwin(&g)));
1271  } else if (!strncmp(buff, "zcrypt ", 7)) {
1272    owl_function_zcrypt(buff, owl_editwin_get_text(owl_global_get_typwin(&g)));
1273  } else if (!strncmp(buff, "aimwrite ", 9)) {
1274    owl_function_aimwrite(buff+9);
1275  } else if (!strncmp(buff, "loopwrite", 9) || !strncmp(buff, "loopwrite ", 10)) {
1276    owl_function_loopwrite();
1277  } else if (!strncmp(buff, "aimlogin ", 9)) {
1278    ptr=owl_sprintf("%s %s", buff, owl_global_get_response(&g));
1279    owl_function_command(ptr);
1280    owl_free(ptr);
1281  } else {
1282    owl_function_error("Internal error: invalid buffercommand %s", buff);
1283  }
1284}
1285
1286void owl_function_debugmsg(char *fmt, ...)
1287{
1288  FILE *file;
1289  time_t now;
1290  char buff1[LINE], buff2[LINE];
1291  va_list ap;
1292  va_start(ap, fmt);
1293
1294  if (!owl_global_is_debug_fast(&g)) return;
1295
1296  file=fopen(owl_global_get_debug_file(&g), "a");
1297  if (!file) return;
1298
1299  now=time(NULL);
1300  strcpy(buff1, ctime(&now));
1301  buff1[strlen(buff1)-1]='\0';
1302
1303  owl_global_get_runtime_string(&g, buff2);
1304 
1305  fprintf(file, "[%i -  %s - %s]: ", (int) getpid(), buff1, buff2);
1306  vfprintf(file, fmt, ap);
1307  fprintf(file, "\n");
1308  fclose(file);
1309
1310  va_end(ap);
1311}
1312
1313void owl_function_refresh()
1314{
1315  owl_function_resize();
1316}
1317
1318void owl_function_beep()
1319{
1320  if (owl_global_is_bell(&g)) {
1321    beep();
1322    owl_global_set_needrefresh(&g); /* do we really need this? */
1323  }
1324}
1325
1326void owl_function_subscribe(char *class, char *inst, char *recip)
1327{
1328  int ret;
1329
1330  ret=owl_zephyr_sub(class, inst, recip);
1331  if (ret) {
1332    owl_function_error("Error subscribing.");
1333  } else {
1334    owl_function_makemsg("Subscribed.");
1335  }
1336}
1337
1338void owl_function_unsubscribe(char *class, char *inst, char *recip)
1339{
1340  int ret;
1341
1342  ret=owl_zephyr_unsub(class, inst, recip);
1343  if (ret) {
1344    owl_function_error("Error subscribing.");
1345  } else {
1346    owl_function_makemsg("Unsubscribed.");
1347  }
1348}
1349
1350void owl_function_set_cursor(WINDOW *win)
1351{
1352  wnoutrefresh(win);
1353}
1354
1355void owl_function_full_redisplay()
1356{
1357  redrawwin(owl_global_get_curs_recwin(&g));
1358  redrawwin(owl_global_get_curs_sepwin(&g));
1359  redrawwin(owl_global_get_curs_typwin(&g));
1360  redrawwin(owl_global_get_curs_msgwin(&g));
1361
1362  wnoutrefresh(owl_global_get_curs_recwin(&g));
1363  wnoutrefresh(owl_global_get_curs_sepwin(&g));
1364  wnoutrefresh(owl_global_get_curs_typwin(&g));
1365  wnoutrefresh(owl_global_get_curs_msgwin(&g));
1366 
1367  sepbar("");
1368  owl_function_makemsg("");
1369
1370  owl_global_set_needrefresh(&g);
1371}
1372
1373void owl_function_popless_text(char *text)
1374{
1375  owl_popwin *pw;
1376  owl_viewwin *v;
1377
1378  pw=owl_global_get_popwin(&g);
1379  v=owl_global_get_viewwin(&g);
1380
1381  owl_popwin_up(pw);
1382  owl_viewwin_init_text(v, owl_popwin_get_curswin(pw),
1383                        owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1384                        text);
1385  owl_popwin_refresh(pw);
1386  owl_viewwin_redisplay(v, 0);
1387  owl_global_set_needrefresh(&g);
1388}
1389
1390void owl_function_popless_fmtext(owl_fmtext *fm)
1391{
1392  owl_popwin *pw;
1393  owl_viewwin *v;
1394
1395  pw=owl_global_get_popwin(&g);
1396  v=owl_global_get_viewwin(&g);
1397
1398  owl_popwin_up(pw);
1399  owl_viewwin_init_fmtext(v, owl_popwin_get_curswin(pw),
1400                   owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1401                   fm);
1402  owl_popwin_refresh(pw);
1403  owl_viewwin_redisplay(v, 0);
1404  owl_global_set_needrefresh(&g);
1405}
1406
1407void owl_function_popless_file(char *filename)
1408{
1409  owl_fmtext fm;
1410  FILE *file;
1411  char buff[1024];
1412
1413  file=fopen(filename, "r");
1414  if (!file) {
1415    owl_function_error("Could not open file: %s", filename);
1416    return;
1417  }
1418
1419  owl_fmtext_init_null(&fm);
1420  while (fgets(buff, 1024, file)) {
1421    owl_fmtext_append_normal(&fm, buff);
1422    /*    owl_fmtext_append_normal(&fm, "\n"); */
1423  }
1424
1425  owl_function_popless_fmtext(&fm);
1426  owl_fmtext_free(&fm);
1427  fclose(file);
1428}
1429
1430void owl_function_about()
1431{
1432  char buff[5000];
1433
1434  sprintf(buff, "This is owl version %s\n", OWL_VERSION_STRING);
1435  strcat(buff, "\nOwl was written by James Kretchmar at the Massachusetts\n");
1436  strcat(buff, "Institute of Technology.  The first version, 0.5, was\n");
1437  strcat(buff, "released in March 2002.\n");
1438  strcat(buff, "\n");
1439  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
1440  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
1441  strcat(buff, "between Witches and Wizards.\n");
1442  strcat(buff, "\n");
1443  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
1444  strcat(buff, "\n");
1445  strcat(buff, "Permission to use, copy, modify, and distribute this\n");
1446  strcat(buff, "software and its documentation for any purpose and without\n");
1447  strcat(buff, "fee is hereby granted, provided that the above copyright\n");
1448  strcat(buff, "notice and this permission notice appear in all copies\n");
1449  strcat(buff, "and in supporting documentation.  No representation is\n");
1450  strcat(buff, "made about the suitability of this software for any\n");
1451  strcat(buff, "purpose.  It is provided \"as is\" without express\n");
1452  strcat(buff, "or implied warranty.\n");
1453  owl_function_popless_text(buff);
1454}
1455
1456void owl_function_info()
1457{
1458  owl_message *m;
1459  owl_fmtext fm, attrfm;
1460  char buff[10000];
1461  owl_view *v;
1462#ifdef HAVE_LIBZEPHYR
1463  ZNotice_t *n;
1464#endif
1465
1466  owl_fmtext_init_null(&fm);
1467 
1468  v=owl_global_get_current_view(&g);
1469  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1470  if (!m || owl_view_get_size(v)==0) {
1471    owl_function_error("No message selected\n");
1472    return;
1473  }
1474
1475  owl_fmtext_append_bold(&fm, "General Information:\n");
1476  owl_fmtext_append_normal(&fm, "  Msg Id    : ");
1477  sprintf(buff, "%i", owl_message_get_id(m));
1478  owl_fmtext_append_normal(&fm, buff);
1479  owl_fmtext_append_normal(&fm, "\n");
1480
1481  owl_fmtext_append_normal(&fm, "  Type      : ");
1482  owl_fmtext_append_bold(&fm, owl_message_get_type(m));
1483  owl_fmtext_append_normal(&fm, "\n");
1484
1485  if (owl_message_is_direction_in(m)) {
1486    owl_fmtext_append_normal(&fm, "  Direction : in\n");
1487  } else if (owl_message_is_direction_out(m)) {
1488    owl_fmtext_append_normal(&fm, "  Direction : out\n");
1489  } else if (owl_message_is_direction_none(m)) {
1490    owl_fmtext_append_normal(&fm, "  Direction : none\n");
1491  } else {
1492    owl_fmtext_append_normal(&fm, "  Direction : unknown\n");
1493  }
1494
1495  owl_fmtext_append_normal(&fm, "  Time      : ");
1496  owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1497  owl_fmtext_append_normal(&fm, "\n");
1498
1499  if (!owl_message_is_type_admin(m)) {
1500    owl_fmtext_append_normal(&fm, "  Sender    : ");
1501    owl_fmtext_append_normal(&fm, owl_message_get_sender(m));
1502    owl_fmtext_append_normal(&fm, "\n");
1503   
1504    owl_fmtext_append_normal(&fm, "  Recipient : ");
1505    owl_fmtext_append_normal(&fm, owl_message_get_recipient(m));
1506    owl_fmtext_append_normal(&fm, "\n");
1507  }
1508   
1509  if (owl_message_is_type_zephyr(m)) {
1510    owl_fmtext_append_bold(&fm, "\nZephyr Specific Information:\n");
1511   
1512    owl_fmtext_append_normal(&fm, "  Class     : ");
1513    owl_fmtext_append_normal(&fm, owl_message_get_class(m));
1514    owl_fmtext_append_normal(&fm, "\n");
1515    owl_fmtext_append_normal(&fm, "  Instance  : ");
1516    owl_fmtext_append_normal(&fm, owl_message_get_instance(m));
1517    owl_fmtext_append_normal(&fm, "\n");
1518    owl_fmtext_append_normal(&fm, "  Opcode    : ");
1519    owl_fmtext_append_normal(&fm, owl_message_get_opcode(m));
1520    owl_fmtext_append_normal(&fm, "\n");
1521   
1522    owl_fmtext_append_normal(&fm, "  Time      : ");
1523    owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1524    owl_fmtext_append_normal(&fm, "\n");
1525#ifdef HAVE_LIBZEPHYR
1526    if (owl_message_is_direction_in(m)) {
1527      char *ptr, tmpbuff[1024];
1528      int i, j, fields, len;
1529
1530      n=owl_message_get_notice(m);
1531
1532      if (!owl_message_is_pseudo(m)) {
1533        owl_fmtext_append_normal(&fm, "  Kind      : ");
1534        if (n->z_kind==UNSAFE) {
1535          owl_fmtext_append_normal(&fm, "UNSAFE\n");
1536        } else if (n->z_kind==UNACKED) {
1537          owl_fmtext_append_normal(&fm, "UNACKED\n");
1538        } else if (n->z_kind==ACKED) {
1539          owl_fmtext_append_normal(&fm, "ACKED\n");
1540        } else if (n->z_kind==HMACK) {
1541          owl_fmtext_append_normal(&fm, "HMACK\n");
1542        } else if (n->z_kind==HMCTL) {
1543          owl_fmtext_append_normal(&fm, "HMCTL\n");
1544        } else if (n->z_kind==SERVACK) {
1545          owl_fmtext_append_normal(&fm, "SERVACK\n");
1546        } else if (n->z_kind==SERVNAK) {
1547          owl_fmtext_append_normal(&fm, "SERVNACK\n");
1548        } else if (n->z_kind==CLIENTACK) {
1549          owl_fmtext_append_normal(&fm, "CLIENTACK\n");
1550        } else if (n->z_kind==STAT) {
1551          owl_fmtext_append_normal(&fm, "STAT\n");
1552        } else {
1553          owl_fmtext_append_normal(&fm, "ILLEGAL VALUE\n");
1554        }
1555      }
1556      owl_fmtext_append_normal(&fm, "  Host      : ");
1557      owl_fmtext_append_normal(&fm, owl_message_get_hostname(m));
1558
1559      if (!owl_message_is_pseudo(m)) {
1560        owl_fmtext_append_normal(&fm, "\n");
1561        sprintf(buff, "  Port      : %i\n", n->z_port);
1562        owl_fmtext_append_normal(&fm, buff);
1563
1564        owl_fmtext_append_normal(&fm,    "  Auth      : ");
1565        owl_fmtext_append_normal(&fm, owl_zephyr_get_authstr(n));
1566        owl_fmtext_append_normal(&fm, "\n");
1567       
1568        /* fix this */
1569        sprintf(buff, "  Checkd Ath: %i\n", n->z_checked_auth);
1570        sprintf(buff, "%s  Multi notc: %s\n", buff, n->z_multinotice);
1571        sprintf(buff, "%s  Num other : %i\n", buff, n->z_num_other_fields);
1572        sprintf(buff, "%s  Msg Len   : %i\n", buff, n->z_message_len);
1573        owl_fmtext_append_normal(&fm, buff);
1574       
1575        sprintf(buff, "  Fields    : %i\n", owl_zephyr_get_num_fields(n));
1576        owl_fmtext_append_normal(&fm, buff);
1577       
1578        fields=owl_zephyr_get_num_fields(n);
1579        for (i=0; i<fields; i++) {
1580          sprintf(buff, "  Field %i   : ", i+1);
1581         
1582          ptr=owl_zephyr_get_field(n, i+1);
1583          len=strlen(ptr);
1584          if (len<30) {
1585            strncpy(tmpbuff, ptr, len);
1586            tmpbuff[len]='\0';
1587          } else {
1588            strncpy(tmpbuff, ptr, 30);
1589            tmpbuff[30]='\0';
1590            strcat(tmpbuff, "...");
1591          }
1592          owl_free(ptr);
1593         
1594          for (j=0; j<strlen(tmpbuff); j++) {
1595            if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1596            if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1597          }
1598         
1599          strcat(buff, tmpbuff);
1600          strcat(buff, "\n");
1601          owl_fmtext_append_normal(&fm, buff);
1602        }
1603        owl_fmtext_append_normal(&fm, "  Default Fm:");
1604        owl_fmtext_append_normal(&fm, n->z_default_format);
1605      }
1606     
1607    }
1608#endif   
1609  }
1610
1611  if (owl_message_is_type_aim(m)) {
1612    owl_fmtext_append_bold(&fm, "\nAIM Specific Information:\n");
1613  }
1614
1615  owl_fmtext_append_bold(&fm, "\nOwl Message Attributes:\n");
1616  owl_message_attributes_tofmtext(m, &attrfm);
1617  owl_fmtext_append_fmtext(&fm, &attrfm);
1618 
1619  owl_function_popless_fmtext(&fm);
1620  owl_fmtext_free(&fm);
1621  owl_fmtext_free(&attrfm);
1622}
1623
1624/* print the current message in a popup window.
1625 * Use the 'default' style regardless of whatever
1626 * style the user may be using
1627 */
1628void owl_function_curmsg_to_popwin()
1629{
1630  owl_popwin *pw;
1631  owl_view *v;
1632  owl_message *m;
1633  owl_style *s;
1634  owl_fmtext fm;
1635
1636  v=owl_global_get_current_view(&g);
1637  s=owl_global_get_style_by_name(&g, "default");
1638  pw=owl_global_get_popwin(&g);
1639
1640  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1641
1642  if (!m || owl_view_get_size(v)==0) {
1643    owl_function_error("No current message");
1644    return;
1645  }
1646
1647  owl_fmtext_init_null(&fm);
1648  owl_style_get_formattext(s, &fm, m);
1649
1650  owl_function_popless_fmtext(&fm);
1651  owl_fmtext_free(&fm);
1652}
1653
1654void owl_function_page_curmsg(int step)
1655{
1656  /* scroll down or up within the current message IF the message is truncated */
1657
1658  int offset, curmsg, lines;
1659  owl_view *v;
1660  owl_message *m;
1661
1662  offset=owl_global_get_curmsg_vert_offset(&g);
1663  v=owl_global_get_current_view(&g);
1664  curmsg=owl_global_get_curmsg(&g);
1665  m=owl_view_get_element(v, curmsg);
1666  if (!m || owl_view_get_size(v)==0) return;
1667  lines=owl_message_get_numlines(m);
1668
1669  if (offset==0) {
1670    /* Bail if the curmsg isn't the last one displayed */
1671    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
1672      owl_function_makemsg("The entire message is already displayed");
1673      return;
1674    }
1675   
1676    /* Bail if we're not truncated */
1677    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
1678      owl_function_makemsg("The entire message is already displayed");
1679      return;
1680    }
1681  }
1682 
1683 
1684  /* don't scroll past the last line */
1685  if (step>0) {
1686    if (offset+step > lines-1) {
1687      owl_global_set_curmsg_vert_offset(&g, lines-1);
1688    } else {
1689      owl_global_set_curmsg_vert_offset(&g, offset+step);
1690    }
1691  }
1692
1693  /* would we be before the beginning of the message? */
1694  if (step<0) {
1695    if (offset+step<0) {
1696      owl_global_set_curmsg_vert_offset(&g, 0);
1697    } else {
1698      owl_global_set_curmsg_vert_offset(&g, offset+step);
1699    }
1700  }
1701 
1702  /* redisplay */
1703  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1704  owl_global_set_needrefresh(&g);
1705}
1706
1707void owl_function_resize_typwin(int newsize)
1708{
1709  owl_global_set_typwin_lines(&g, newsize);
1710  owl_function_resize();
1711}
1712
1713void owl_function_typwin_grow()
1714{
1715  int i;
1716
1717  i=owl_global_get_typwin_lines(&g);
1718  owl_function_resize_typwin(i+1);
1719}
1720
1721void owl_function_typwin_shrink()
1722{
1723  int i;
1724
1725  i=owl_global_get_typwin_lines(&g);
1726  if (i>2) {
1727    owl_function_resize_typwin(i-1);
1728  }
1729}
1730
1731void owl_function_mainwin_pagedown()
1732{
1733  int i;
1734
1735  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1736  if (i<0) return;
1737  if (owl_mainwin_is_last_msg_truncated(owl_global_get_mainwin(&g))
1738      && (owl_global_get_curmsg(&g) < i)
1739      && (i>0)) {
1740    i--;
1741  }
1742  owl_global_set_curmsg(&g, i);
1743  owl_function_nextmsg();
1744}
1745
1746void owl_function_mainwin_pageup()
1747{
1748  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1749  owl_function_prevmsg();
1750}
1751
1752void owl_function_getsubs()
1753{
1754  char *buff;
1755
1756  buff=owl_zephyr_getsubs();
1757
1758  if (buff) {
1759    owl_function_popless_text(buff);
1760  } else {
1761    owl_function_popless_text("Error getting subscriptions");
1762  }
1763           
1764  owl_free(buff);
1765}
1766
1767#define PABUFLEN 5000
1768void owl_function_printallvars()
1769{
1770  char buff[PABUFLEN], *pos, *name;
1771  owl_list varnames;
1772  int i, numvarnames, rem;
1773
1774  pos = buff;
1775  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1776  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1777  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1778  rem = (buff+PABUFLEN)-pos-1;
1779  numvarnames = owl_list_get_size(&varnames);
1780  for (i=0; i<numvarnames; i++) {
1781    name = owl_list_get_element(&varnames, i);
1782    if (name && name[0]!='_') {
1783      rem = (buff+PABUFLEN)-pos-1;   
1784      pos += snprintf(pos, rem, "\n%-20s = ", name);
1785      rem = (buff+PABUFLEN)-pos-1;   
1786      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1787      pos = buff+strlen(buff);
1788    }
1789  }
1790  rem = (buff+PABUFLEN)-pos-1;   
1791  snprintf(pos, rem, "\n");
1792  owl_variable_dict_namelist_free(&varnames);
1793 
1794  owl_function_popless_text(buff);
1795}
1796
1797void owl_function_show_variables()
1798{
1799  owl_list varnames;
1800  owl_fmtext fm; 
1801  int i, numvarnames;
1802  char *varname;
1803
1804  owl_fmtext_init_null(&fm);
1805  owl_fmtext_append_bold(&fm, 
1806      "Variables: (use 'show variable <name>' for details)\n");
1807  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1808  numvarnames = owl_list_get_size(&varnames);
1809  for (i=0; i<numvarnames; i++) {
1810    varname = owl_list_get_element(&varnames, i);
1811    if (varname && varname[0]!='_') {
1812      owl_variable_describe(owl_global_get_vardict(&g), varname, &fm);
1813    }
1814  }
1815  owl_variable_dict_namelist_free(&varnames);
1816  owl_function_popless_fmtext(&fm);
1817  owl_fmtext_free(&fm);
1818}
1819
1820void owl_function_show_variable(char *name)
1821{
1822  owl_fmtext fm; 
1823
1824  owl_fmtext_init_null(&fm);
1825  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1826  owl_function_popless_fmtext(&fm);
1827  owl_fmtext_free(&fm); 
1828}
1829
1830/* note: this applies to global message list, not to view.
1831 * If flag is 1, deletes.  If flag is 0, undeletes. */
1832void owl_function_delete_by_id(int id, int flag)
1833{
1834  owl_messagelist *ml;
1835  owl_message *m;
1836  ml = owl_global_get_msglist(&g);
1837  m = owl_messagelist_get_by_id(ml, id);
1838  if (m) {
1839    if (flag == 1) {
1840      owl_message_mark_delete(m);
1841    } else if (flag == 0) {
1842      owl_message_unmark_delete(m);
1843    }
1844    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1845    owl_global_set_needrefresh(&g);
1846  } else {
1847    owl_function_error("No message with id %d: unable to mark for (un)delete",id);
1848  }
1849}
1850
1851void owl_function_delete_automsgs()
1852{
1853  /* mark for deletion all messages in the current view that match the
1854   * 'trash' filter */
1855
1856  int i, j, count;
1857  owl_message *m;
1858  owl_view *v;
1859  owl_filter *f;
1860
1861  /* get the trash filter */
1862  f=owl_global_get_filter(&g, "trash");
1863  if (!f) {
1864    owl_function_error("No trash filter defined");
1865    return;
1866  }
1867
1868  v=owl_global_get_current_view(&g);
1869
1870  count=0;
1871  j=owl_view_get_size(v);
1872  for (i=0; i<j; i++) {
1873    m=owl_view_get_element(v, i);
1874    if (owl_filter_message_match(f, m)) {
1875      count++;
1876      owl_message_mark_delete(m);
1877    }
1878  }
1879  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1880  owl_function_makemsg("%i messages marked for deletion", count);
1881  owl_global_set_needrefresh(&g);
1882}
1883
1884void owl_function_status()
1885{
1886  char buff[5000];
1887  time_t start;
1888  int up, days, hours, minutes;
1889  owl_fmtext fm;
1890
1891  owl_fmtext_init_null(&fm);
1892
1893  start=owl_global_get_starttime(&g);
1894
1895  owl_fmtext_append_normal(&fm, "General Information:\n");
1896
1897  owl_fmtext_append_normal(&fm, "  Version: ");
1898  owl_fmtext_append_normal(&fm, OWL_VERSION_STRING);
1899  owl_fmtext_append_normal(&fm, "\n");
1900
1901  owl_fmtext_append_normal(&fm, "  Startup Arugments: ");
1902  owl_fmtext_append_normal(&fm, owl_global_get_startupargs(&g));
1903  owl_fmtext_append_normal(&fm, "\n");
1904
1905  owl_fmtext_append_normal(&fm, "  Current Directory: ");
1906  (void) getcwd(buff, MAXPATHLEN);
1907  owl_fmtext_append_normal(&fm, buff);
1908  owl_fmtext_append_normal(&fm, "\n");
1909
1910  sprintf(buff, "  Startup Time: %s", ctime(&start));
1911  owl_fmtext_append_normal(&fm, buff);
1912
1913  up=owl_global_get_runtime(&g);
1914  days=up/86400;
1915  up-=days*86400;
1916  hours=up/3600;
1917  up-=hours*3600;
1918  minutes=up/60;
1919  up-=minutes*60;
1920  sprintf(buff, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
1921  owl_fmtext_append_normal(&fm, buff);
1922
1923  owl_fmtext_append_normal(&fm, "\nProtocol Options:\n");
1924  owl_fmtext_append_normal(&fm, "  Zephyr included    : ");
1925  if (owl_global_is_havezephyr(&g)) {
1926    owl_fmtext_append_normal(&fm, "yes\n");
1927  } else {
1928    owl_fmtext_append_normal(&fm, "no\n");
1929  }
1930  owl_fmtext_append_normal(&fm, "  AIM included       : yes\n");
1931  owl_fmtext_append_normal(&fm, "  Loopback included  : yes\n");
1932
1933
1934  owl_fmtext_append_normal(&fm, "\nBuild Options:\n");
1935  owl_fmtext_append_normal(&fm, "  Stderr redirection : ");
1936#if OWL_STDERR_REDIR
1937  owl_fmtext_append_normal(&fm, "yes\n");
1938#else
1939  owl_fmtext_append_normal(&fm, "no\n");
1940#endif
1941 
1942
1943  owl_fmtext_append_normal(&fm, "\nMemory Usage:\n");
1944  owl_fmtext_append_normal(&fm, "  Not currently available.\n");
1945  /*
1946  sprintf(buff, "%sMemory Malloced: %i\n", buff, owl_global_get_malloced(&g));
1947  sprintf(buff, "%sMemory Freed: %i\n", buff, owl_global_get_freed(&g));
1948  sprintf(buff, "%sMemory In Use: %i\n", buff, owl_global_get_meminuse(&g));
1949  */
1950
1951  owl_fmtext_append_normal(&fm, "\nAIM Status:\n");
1952  owl_fmtext_append_normal(&fm, "  Logged in: ");
1953  if (owl_global_is_aimloggedin(&g)) {
1954    owl_fmtext_append_normal(&fm, owl_global_get_aim_screenname(&g));
1955    owl_fmtext_append_normal(&fm, "\n");
1956  } else {
1957    owl_fmtext_append_normal(&fm, "(not logged in)\n");
1958  }
1959
1960  owl_fmtext_append_normal(&fm, "  Processing events: ");
1961  if (owl_global_is_doaimevents(&g)) {
1962    owl_fmtext_append_normal(&fm, "yes\n");
1963  } else {
1964    owl_fmtext_append_normal(&fm, "no\n");
1965  }
1966
1967  owl_function_popless_fmtext(&fm);
1968  owl_fmtext_free(&fm);
1969}
1970
1971void owl_function_show_term()
1972{
1973  owl_fmtext fm;
1974  char buff[LINE];
1975
1976  owl_fmtext_init_null(&fm);
1977  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
1978          owl_global_get_lines(&g),
1979          owl_global_get_cols(&g));
1980  owl_fmtext_append_normal(&fm, buff);
1981
1982  if (owl_global_get_hascolors(&g)) {
1983    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1984    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1985    owl_fmtext_append_normal(&fm, buff);
1986    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1987    owl_fmtext_append_normal(&fm, buff);
1988  } else {
1989    owl_fmtext_append_normal(&fm, "Color: No\n");
1990  }
1991
1992  owl_function_popless_fmtext(&fm);
1993  owl_fmtext_free(&fm);
1994}
1995
1996/* if type = 0 then normal reply.
1997 * if type = 1 then it's a reply to sender
1998 * if enter = 0 then allow the command to be edited
1999 * if enter = 1 then don't wait for editing
2000 */
2001void owl_function_reply(int type, int enter)
2002{
2003  char *buff=NULL, *oldbuff;
2004  owl_message *m;
2005  owl_filter *f;
2006 
2007  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
2008    owl_function_error("No message selected");
2009  } else {
2010    char *class, *inst, *to, *cc=NULL;
2011   
2012    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
2013    if (!m) {
2014      owl_function_error("No message selected");
2015      return;
2016    }
2017
2018    /* first check if we catch the reply-lockout filter */
2019    f=owl_global_get_filter(&g, "reply-lockout");
2020    if (f) {
2021      if (owl_filter_message_match(f, m)) {
2022        owl_function_error("Sorry, replies to this message have been disabled by the reply-lockout filter");
2023        return;
2024      }
2025    }
2026
2027    /* admin */
2028    if (owl_message_is_type_admin(m)) {
2029      owl_function_error("You cannot reply to an admin message");
2030      return;
2031    }
2032
2033    /* loopback */
2034    if (owl_message_is_type_loopback(m)) {
2035      owl_function_loopwrite_setup();
2036      return;
2037    }
2038
2039    /* zephyr */
2040    if (owl_message_is_type_zephyr(m)) {
2041      /* if it's a zephyr we sent, send it out the same way again */
2042      if (owl_message_is_direction_out(m)) {
2043        owl_function_zwrite_setup(owl_message_get_zwriteline(m));
2044        owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
2045        return;
2046      }
2047
2048      /* Special case a personal reply to a webzephyr user on a class */
2049      if ((type==1) && !strcasecmp(owl_message_get_opcode(m), OWL_WEBZEPHYR_OPCODE)) {
2050        class=OWL_WEBZEPHYR_CLASS;
2051        inst=owl_message_get_sender(m);
2052        to=OWL_WEBZEPHYR_PRINCIPAL;
2053      } else if (!strcasecmp(owl_message_get_class(m), OWL_WEBZEPHYR_CLASS) && owl_message_is_loginout(m)) {
2054        /* Special case LOGIN/LOGOUT notifications on class "webzephyr" */
2055        class=OWL_WEBZEPHYR_CLASS;
2056        inst=owl_message_get_instance(m);
2057        to=OWL_WEBZEPHYR_PRINCIPAL;
2058      } else if (owl_message_is_loginout(m)) {
2059        /* Normal LOGIN/LOGOUT messages */
2060        class="MESSAGE";
2061        inst="PERSONAL";
2062        to=owl_message_get_sender(m);
2063      } else if (type==1) {
2064        /* Personal reply */
2065        class="MESSAGE";
2066        inst="PERSONAL";
2067        to=owl_message_get_sender(m);
2068      } else {
2069        /* General reply */
2070        class=owl_message_get_class(m);
2071        inst=owl_message_get_instance(m);
2072        to=owl_message_get_recipient(m);
2073        cc=owl_message_get_cc(m);
2074        if (!strcmp(to, "") || !strcmp(to, "*")) {
2075          to="";
2076        } else if (to[0]=='@') {
2077          /* leave it, to get the realm */
2078        } else {
2079          to=owl_message_get_sender(m);
2080        }
2081      }
2082       
2083      /* create the command line */
2084      if (!strcasecmp(owl_message_get_opcode(m), "CRYPT")) {
2085        buff=owl_strdup("zcrypt");
2086      } else {
2087        buff = owl_strdup("zwrite");
2088      }
2089      if (strcasecmp(class, "message")) {
2090        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
2091        owl_free(oldbuff);
2092      }
2093      if (strcasecmp(inst, "personal")) {
2094        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
2095        owl_free(oldbuff);
2096      }
2097      if (*to != '\0') {
2098        char *tmp, *oldtmp, *tmp2;
2099        tmp=short_zuser(to);
2100        if (cc) {
2101          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
2102          owl_free(oldtmp);
2103          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
2104          owl_free(oldbuff);
2105        } else {
2106          if (owl_global_is_smartstrip(&g)) {
2107            tmp2=tmp;
2108            tmp=owl_zephyr_smartstripped_user(tmp2);
2109            owl_free(tmp2);
2110          }
2111          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
2112          owl_free(oldbuff);
2113        }
2114        owl_free(tmp);
2115      }
2116      if (cc) owl_free(cc);
2117    }
2118
2119    /* aim */
2120    if (owl_message_is_type_aim(m)) {
2121      if (owl_message_is_direction_out(m)) {
2122        buff=owl_sprintf("aimwrite %s", owl_message_get_recipient(m));
2123      } else {
2124        buff=owl_sprintf("aimwrite %s", owl_message_get_sender(m));
2125      }
2126    }
2127   
2128    if (enter) {
2129      owl_history *hist = owl_global_get_cmd_history(&g);
2130      owl_history_store(hist, buff);
2131      owl_history_reset(hist);
2132      owl_function_command_norv(buff);
2133    } else {
2134      owl_function_start_command(buff);
2135    }
2136    owl_free(buff);
2137  }
2138}
2139
2140void owl_function_zlocate(int argc, char **argv, int auth)
2141{
2142  owl_fmtext fm;
2143  char *ptr, buff[LINE];
2144  int i;
2145
2146  owl_fmtext_init_null(&fm);
2147
2148  for (i=0; i<argc; i++) {
2149    ptr=long_zuser(argv[i]);
2150    owl_zephyr_zlocate(ptr, buff, auth);
2151    owl_fmtext_append_normal(&fm, buff);
2152    owl_free(ptr);
2153  }
2154
2155  owl_function_popless_fmtext(&fm);
2156  owl_fmtext_free(&fm);
2157}
2158
2159void owl_function_start_command(char *line)
2160{
2161  int i, j;
2162  owl_editwin *tw;
2163
2164  tw=owl_global_get_typwin(&g);
2165  owl_global_set_typwin_active(&g);
2166  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
2167                        owl_global_get_cmd_history(&g));
2168
2169  owl_editwin_set_locktext(tw, "command: ");
2170  owl_global_set_needrefresh(&g);
2171
2172  j=strlen(line);
2173  for (i=0; i<j; i++) {
2174    owl_editwin_process_char(tw, line[i]);
2175  }
2176  owl_editwin_redisplay(tw, 0);
2177
2178  owl_context_set_editline(owl_global_get_context(&g), tw);
2179  owl_function_activate_keymap("editline");
2180}
2181
2182void owl_function_start_question(char *line)
2183{
2184  owl_editwin *tw;
2185
2186  tw=owl_global_get_typwin(&g);
2187  owl_global_set_typwin_active(&g);
2188  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2189
2190  owl_editwin_set_locktext(tw, line);
2191  owl_global_set_needrefresh(&g);
2192
2193  owl_editwin_redisplay(tw, 0);
2194
2195  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2196  owl_function_activate_keymap("editresponse");
2197}
2198
2199void owl_function_start_password(char *line)
2200{
2201  owl_editwin *tw;
2202
2203  tw=owl_global_get_typwin(&g);
2204  owl_global_set_typwin_active(&g);
2205  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2206  owl_editwin_set_echochar(tw, '*');
2207
2208  owl_editwin_set_locktext(tw, line);
2209  owl_global_set_needrefresh(&g);
2210
2211  owl_editwin_redisplay(tw, 0);
2212
2213  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2214  owl_function_activate_keymap("editresponse");
2215}
2216
2217char *owl_function_exec(int argc, char **argv, char *buff, int type)
2218{
2219  /* if type == 1 display in a popup
2220   * if type == 2 display an admin messages
2221   * if type == 0 return output
2222   * else display in a popup
2223   */
2224  char *newbuff, *redirect = " 2>&1 < /dev/null";
2225  char *out, buff2[1024];
2226  int size;
2227  FILE *p;
2228
2229#if OWL_STDERR_REDIR
2230  redirect = " < /dev/null";
2231#endif
2232
2233  if (argc<2) {
2234    owl_function_error("Wrong number of arguments to the exec command");
2235    return NULL;
2236  }
2237
2238  buff = skiptokens(buff, 1);
2239  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
2240  strcpy(newbuff, buff);
2241  strcat(newbuff, redirect);
2242
2243  if (type == 1) {
2244    owl_popexec_new(newbuff);
2245  } else {
2246    p=popen(newbuff, "r");
2247    out=owl_malloc(1024);
2248    size=1024;
2249    strcpy(out, "");
2250    while (fgets(buff2, 1024, p)!=NULL) {
2251      size+=1024;
2252      out=owl_realloc(out, size);
2253      strcat(out, buff2);
2254    }
2255    pclose(p);
2256   
2257    if (type==1) {
2258      owl_function_popless_text(out);
2259    } else if (type==0) {
2260      return out;
2261    } else if (type==2) {
2262      owl_function_adminmsg(buff, out);
2263    } else {
2264      owl_function_popless_text(out);
2265    }
2266    owl_free(out);
2267  }
2268  return NULL;
2269}
2270
2271char *owl_function_perl(int argc, char **argv, char *buff, int type)
2272{
2273  /* if type == 1 display in a popup
2274   * if type == 2 display an admin messages
2275   * if type == 0 return output
2276   * else display in a popup
2277   */
2278  char *perlout;
2279
2280  if (argc<2) {
2281    owl_function_error("Wrong number of arguments to perl command");
2282    return NULL;
2283  }
2284
2285  /* consume first token (argv[0]) */
2286  buff = skiptokens(buff, 1);
2287
2288  perlout = owl_perlconfig_execute(buff);
2289  if (perlout) { 
2290    if (type==1) {
2291      owl_function_popless_text(perlout);
2292    } else if (type==2) {
2293      owl_function_adminmsg(buff, perlout);
2294    } else if (type==0) {
2295      return perlout;
2296    } else {
2297      owl_function_popless_text(perlout);
2298    }
2299    owl_free(perlout);
2300  }
2301  return NULL;
2302}
2303
2304void owl_function_change_currentview_filter(char *filtname)
2305{
2306  owl_view *v;
2307  owl_filter *f;
2308  int curid=-1, newpos, curmsg;
2309  owl_message *curm=NULL;
2310
2311  v=owl_global_get_current_view(&g);
2312
2313  curmsg=owl_global_get_curmsg(&g);
2314  if (curmsg==-1) {
2315    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2316  } else {
2317    curm=owl_view_get_element(v, curmsg);
2318    if (curm) {
2319      curid=owl_message_get_id(curm);
2320      owl_view_save_curmsgid(v, curid);
2321    }
2322  }
2323
2324  f=owl_global_get_filter(&g, filtname);
2325  if (!f) {
2326    owl_function_error("Unknown filter %s", filtname);
2327    return;
2328  }
2329
2330  owl_view_new_filter(v, f);
2331
2332  /* Figure out what to set the current message to.
2333   * - If the view we're leaving has messages in it, go to the closest message
2334   *   to the last message pointed to in that view.
2335   * - If the view we're leaving is empty, try to restore the position
2336   *   from the last time we were in the new view.  */
2337  if (curm) {
2338    newpos = owl_view_get_nearest_to_msgid(v, curid);
2339  } else {
2340    newpos = owl_view_get_nearest_to_saved(v);
2341  }
2342
2343  owl_global_set_curmsg(&g, newpos);
2344  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2345  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2346  owl_global_set_direction_downwards(&g);
2347}
2348
2349void owl_function_create_filter(int argc, char **argv)
2350{
2351  owl_filter *f;
2352  owl_view *v;
2353  int ret, inuse=0;
2354
2355  if (argc < 2) {
2356    owl_function_error("Wrong number of arguments to filter command");
2357    return;
2358  }
2359
2360  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2361
2362  v=owl_global_get_current_view(&g);
2363
2364  /* don't touch the all filter */
2365  if (!strcmp(argv[1], "all")) {
2366    owl_function_error("You may not change the 'all' filter.");
2367    return;
2368  }
2369
2370  /* deal with the case of trying change the filter color */
2371  if (argc==4 && !strcmp(argv[2], "-c")) {
2372    f=owl_global_get_filter(&g, argv[1]);
2373    if (!f) {
2374      owl_function_error("The filter '%s' does not exist.", argv[1]);
2375      return;
2376    }
2377    if (owl_util_string_to_color(argv[3])==-1) {
2378      owl_function_error("The color '%s' is not available.", argv[3]);
2379      return;
2380    }
2381    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
2382    owl_global_set_needrefresh(&g);
2383    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2384    return;
2385  }
2386
2387  /* create the filter and check for errors */
2388  f=owl_malloc(sizeof(owl_filter));
2389  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2390  if (ret==-1) {
2391    owl_free(f);
2392    owl_function_error("Invalid filter");
2393    return;
2394  }
2395
2396  /* if the named filter is in use by the current view, remember it */
2397  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2398    inuse=1;
2399  }
2400
2401  /* if the named filter already exists, nuke it */
2402  if (owl_global_get_filter(&g, argv[1])) {
2403    owl_global_remove_filter(&g, argv[1]);
2404  }
2405
2406  /* add the filter */
2407  owl_global_add_filter(&g, f);
2408
2409  /* if it was in use by the current view then update */
2410  if (inuse) {
2411    owl_function_change_currentview_filter(argv[1]);
2412  }
2413  owl_global_set_needrefresh(&g);
2414  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2415}
2416
2417/* If 'filtername' does not start with 'not-' create a filter named
2418 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2419 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2420 * 'filtername' begins with 'not-' and a filter 'filtername' already
2421 * exists, then do nothing.  If the filter 'filtername' does not
2422 * exist, create it and define it as 'not filter <filtername>'
2423 *
2424 * Returns the name of the negated filter, which the caller must free.
2425 */
2426char *owl_function_create_negative_filter(char *filtername)
2427{
2428  char *newname;
2429  owl_filter *tmpfilt;
2430  char *argv[5];
2431
2432  owl_function_debugmsg("owl_function_create_negative_filter");
2433 
2434  if (!strncmp(filtername, "not-", 4)) {
2435    newname=owl_strdup(filtername+4);
2436  } else {
2437    newname=owl_sprintf("not-%s", filtername);
2438  }
2439
2440  tmpfilt=owl_global_get_filter(&g, newname);
2441  if (!tmpfilt) {
2442    argv[0]="filter"; /* anything is fine here */
2443    argv[1]=newname;
2444    argv[2]="not";
2445    argv[3]="filter";
2446    argv[4]=filtername;
2447    owl_function_create_filter(5, argv);
2448  }
2449
2450  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2451  return(newname);
2452}
2453
2454void owl_function_show_filters()
2455{
2456  owl_list *l;
2457  owl_filter *f;
2458  int i, j;
2459  owl_fmtext fm;
2460
2461  owl_fmtext_init_null(&fm);
2462
2463  l=owl_global_get_filterlist(&g);
2464  j=owl_list_get_size(l);
2465
2466  owl_fmtext_append_bold(&fm, "Filters:\n");
2467
2468  for (i=0; i<j; i++) {
2469    f=owl_list_get_element(l, i);
2470    owl_fmtext_append_normal(&fm, "   ");
2471    if (owl_global_get_hascolors(&g)) {
2472      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
2473    } else {
2474      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2475    }
2476    owl_fmtext_append_normal(&fm, "\n");
2477  }
2478  owl_function_popless_fmtext(&fm);
2479  owl_fmtext_free(&fm);
2480}
2481
2482void owl_function_show_filter(char *name)
2483{
2484  owl_filter *f;
2485  char buff[5000];
2486
2487  f=owl_global_get_filter(&g, name);
2488  if (!f) {
2489    owl_function_error("There is no filter named %s", name);
2490    return;
2491  }
2492  owl_filter_print(f, buff);
2493  owl_function_popless_text(buff);
2494}
2495
2496void owl_function_show_zpunts()
2497{
2498  owl_filter *f;
2499  owl_list *fl;
2500  char buff[5000];
2501  owl_fmtext fm;
2502  int i, j;
2503
2504  owl_fmtext_init_null(&fm);
2505
2506  fl=owl_global_get_puntlist(&g);
2507  j=owl_list_get_size(fl);
2508  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2509
2510  for (i=0; i<j; i++) {
2511    f=owl_list_get_element(fl, i);
2512    owl_filter_print(f, buff);
2513    owl_fmtext_append_normal(&fm, buff);
2514  }
2515  owl_function_popless_fmtext(&fm);
2516  owl_fmtext_free(&fm);
2517}
2518
2519/* Create a filter for a class, instance if one doesn't exist.  If
2520 * instance is NULL then catch all messgaes in the class.  Returns the
2521 * name of the filter, which the caller must free.
2522 */
2523char *owl_function_classinstfilt(char *class, char *instance) 
2524{
2525  owl_list *fl;
2526  owl_filter *f;
2527  char *argbuff, *filtname;
2528  char *tmpclass, *tmpinstance = NULL;
2529  int len;
2530
2531  fl=owl_global_get_filterlist(&g);
2532
2533  /* name for the filter */
2534  len=strlen(class)+30;
2535  if (instance) len+=strlen(instance);
2536  filtname=owl_malloc(len);
2537  if (!instance) {
2538    sprintf(filtname, "class-%s", class);
2539  } else {
2540    sprintf(filtname, "class-%s-instance-%s", class, instance);
2541  }
2542  /* downcase it */
2543  downstr(filtname);
2544  /* turn spaces into dots */
2545  owl_text_tr(filtname, ' ', '.');
2546 
2547  /* if it already exists then go with it.  This lets users override */
2548  if (owl_global_get_filter(&g, filtname)) {
2549    return(filtname);
2550  }
2551
2552  /* create the new filter */
2553  argbuff=owl_malloc(len+20);
2554  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2555  owl_text_tr(tmpclass, ' ', '.');
2556  if (instance) {
2557    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2558    owl_text_tr(tmpinstance, ' ', '.');
2559  }
2560  sprintf(argbuff, "( class ^%s$ )", tmpclass);
2561  if (tmpinstance) {
2562    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, tmpinstance);
2563  }
2564  owl_free(tmpclass);
2565  if (tmpinstance) owl_free(tmpinstance);
2566
2567  f=owl_malloc(sizeof(owl_filter));
2568  owl_filter_init_fromstring(f, filtname, argbuff);
2569
2570  /* add it to the global list */
2571  owl_global_add_filter(&g, f);
2572
2573  owl_free(argbuff);
2574  return(filtname);
2575}
2576
2577/* Create a filter for personal zephyrs to or from the specified
2578 * zephyr user.  Includes login/logout notifications for the user.
2579 * The name of the filter will be 'user-<user>'.  If a filter already
2580 * exists with this name, no new filter will be created.  This allows
2581 * the configuration to override this function.  Returns the name of
2582 * the filter, which the caller must free.
2583 */
2584char *owl_function_zuserfilt(char *user)
2585{
2586  owl_filter *f;
2587  char *argbuff, *longuser, *shortuser, *filtname;
2588
2589  /* stick the local realm on if it's not there */
2590  longuser=long_zuser(user);
2591  shortuser=short_zuser(user);
2592
2593  /* name for the filter */
2594  filtname=owl_malloc(strlen(shortuser)+20);
2595  sprintf(filtname, "user-%s", shortuser);
2596
2597  /* if it already exists then go with it.  This lets users override */
2598  if (owl_global_get_filter(&g, filtname)) {
2599    return(owl_strdup(filtname));
2600  }
2601
2602  /* create the new-internal filter */
2603  f=owl_malloc(sizeof(owl_filter));
2604
2605  argbuff=owl_malloc(strlen(longuser)+1000);
2606  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2607  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2608  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
2609
2610  owl_filter_init_fromstring(f, filtname, argbuff);
2611
2612  /* add it to the global list */
2613  owl_global_add_filter(&g, f);
2614
2615  /* free stuff */
2616  owl_free(argbuff);
2617  owl_free(longuser);
2618  owl_free(shortuser);
2619
2620  return(filtname);
2621}
2622
2623/* Create a filter for AIM IM messages to or from the specified
2624 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2625 * filter already exists with this name, no new filter will be
2626 * created.  This allows the configuration to override this function.
2627 * Returns the name of the filter, which the caller must free.
2628 */
2629char *owl_function_aimuserfilt(char *user)
2630{
2631  owl_filter *f;
2632  char *argbuff, *filtname;
2633
2634  /* name for the filter */
2635  filtname=owl_malloc(strlen(user)+40);
2636  sprintf(filtname, "aimuser-%s", user);
2637
2638  /* if it already exists then go with it.  This lets users override */
2639  if (owl_global_get_filter(&g, filtname)) {
2640    return(owl_strdup(filtname));
2641  }
2642
2643  /* create the new-internal filter */
2644  f=owl_malloc(sizeof(owl_filter));
2645
2646  argbuff=owl_malloc(1000);
2647  sprintf(argbuff,
2648          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2649          user, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), user);
2650
2651  owl_filter_init_fromstring(f, filtname, argbuff);
2652
2653  /* add it to the global list */
2654  owl_global_add_filter(&g, f);
2655
2656  /* free stuff */
2657  owl_free(argbuff);
2658
2659  return(filtname);
2660}
2661
2662char *owl_function_typefilt(char *type)
2663{
2664  owl_filter *f;
2665  char *argbuff, *filtname;
2666
2667  /* name for the filter */
2668  filtname=owl_sprintf("type-%s", type);
2669
2670  /* if it already exists then go with it.  This lets users override */
2671  if (owl_global_get_filter(&g, filtname)) {
2672    return filtname;
2673  }
2674
2675  /* create the new-internal filter */
2676  f=owl_malloc(sizeof(owl_filter));
2677
2678  argbuff = owl_sprintf("type ^%s$", type);
2679
2680  owl_filter_init_fromstring(f, filtname, argbuff);
2681
2682  /* add it to the global list */
2683  owl_global_add_filter(&g, f);
2684
2685  /* free stuff */
2686  owl_free(argbuff);
2687
2688  return filtname;
2689}
2690
2691/* If flag is 1, marks for deletion.  If flag is 0,
2692 * unmarks for deletion. */
2693void owl_function_delete_curview_msgs(int flag)
2694{
2695  owl_view *v;
2696  int i, j;
2697
2698  v=owl_global_get_current_view(&g);
2699  j=owl_view_get_size(v);
2700  for (i=0; i<j; i++) {
2701    if (flag == 1) {
2702      owl_message_mark_delete(owl_view_get_element(v, i));
2703    } else if (flag == 0) {
2704      owl_message_unmark_delete(owl_view_get_element(v, i));
2705    }
2706  }
2707
2708  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2709
2710  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2711}
2712
2713/* Create a filter based on the current message.  Returns the name of
2714 * a filter or null.  The caller must free this name.
2715 *
2716 * if the curmsg is a personal zephyr return a filter name
2717 *    to the zephyr converstaion with that user.
2718 * If the curmsg is a zephyr class message, instance foo, recip *,
2719 *    return a filter name to the class, inst.
2720 * If the curmsg is a zephyr class message and type==0 then
2721 *    return a filter name for just the class.
2722 * If the curmsg is a zephyr class message and type==1 then
2723 *    return a filter name for the class and instance.
2724 * If the curmsg is a personal AIM message returna  filter
2725 *    name to the AIM conversation with that user
2726 */
2727char *owl_function_smartfilter(int type)
2728{
2729  owl_view *v;
2730  owl_message *m;
2731  char *zperson, *filtname=NULL;
2732 
2733  v=owl_global_get_current_view(&g);
2734  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2735
2736  if (!m || owl_view_get_size(v)==0) {
2737    owl_function_error("No message selected\n");
2738    return(NULL);
2739  }
2740
2741  /* very simple handling of admin messages for now */
2742  if (owl_message_is_type_admin(m)) {
2743    return(owl_function_typefilt("admin"));
2744  }
2745
2746  /* very simple handling of loopback messages for now */
2747  if (owl_message_is_type_loopback(m)) {
2748    return(owl_function_typefilt("loopback"));
2749  }
2750
2751  /* aim messages */
2752  if (owl_message_is_type_aim(m)) {
2753    if (owl_message_is_direction_in(m)) {
2754      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2755    } else if (owl_message_is_direction_out(m)) {
2756      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2757    }
2758    return(filtname);
2759  }
2760
2761  /* narrow personal and login messages to the sender or recip as appropriate */
2762  if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2763    if (owl_message_is_type_zephyr(m)) {
2764      if (owl_message_is_direction_in(m)) {
2765        zperson=short_zuser(owl_message_get_sender(m));
2766      } else {
2767        zperson=short_zuser(owl_message_get_recipient(m));
2768      }
2769      filtname=owl_function_zuserfilt(zperson);
2770      owl_free(zperson);
2771      return(filtname);
2772    }
2773    return(NULL);
2774  }
2775
2776  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2777  if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2778    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2779    return(filtname);
2780  }
2781
2782  /* otherwise narrow to the class */
2783  if (type==0) {
2784    filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2785  } else if (type==1) {
2786    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2787  }
2788  return(filtname);
2789}
2790
2791void owl_function_smartzpunt(int type)
2792{
2793  /* Starts a zpunt command based on the current class,instance pair.
2794   * If type=0, uses just class.  If type=1, uses instance as well. */
2795  owl_view *v;
2796  owl_message *m;
2797  char *cmd, *cmdprefix, *mclass, *minst;
2798 
2799  v=owl_global_get_current_view(&g);
2800  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2801
2802  if (!m || owl_view_get_size(v)==0) {
2803    owl_function_error("No message selected\n");
2804    return;
2805  }
2806
2807  /* for now we skip admin messages. */
2808  if (owl_message_is_type_admin(m)
2809      || owl_message_is_loginout(m)
2810      || !owl_message_is_type_zephyr(m)) {
2811    owl_function_error("smartzpunt doesn't support this message type.");
2812    return;
2813  }
2814
2815  mclass = owl_message_get_class(m);
2816  minst = owl_message_get_instance(m);
2817  if (!mclass || !*mclass || *mclass==' '
2818      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2819      || (type && (!minst || !*minst|| *minst==' '))) {
2820    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2821                         mclass, minst);
2822  } else {
2823    cmdprefix = "start-command zpunt ";
2824    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2825    strcpy(cmd, cmdprefix);
2826    strcat(cmd, owl_getquoting(mclass));
2827    strcat(cmd, mclass);
2828    strcat(cmd, owl_getquoting(mclass));
2829    if (type) {
2830      strcat(cmd, " ");
2831      strcat(cmd, owl_getquoting(minst));
2832      strcat(cmd, minst);
2833      strcat(cmd, owl_getquoting(minst));
2834    } else {
2835      strcat(cmd, " *");
2836    }
2837    owl_function_command(cmd);
2838    owl_free(cmd);
2839  }
2840}
2841
2842void owl_function_color_current_filter(char *color)
2843{
2844  owl_filter *f;
2845  char *name;
2846
2847  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2848  f=owl_global_get_filter(&g, name);
2849  if (!f) {
2850    owl_function_error("Unknown filter");
2851    return;
2852  }
2853
2854  /* don't touch the all filter */
2855  if (!strcmp(name, "all")) {
2856    owl_function_error("You may not change the 'all' filter.");
2857    return;
2858  }
2859
2860  /* deal with the case of trying change the filter color */
2861  if (owl_util_string_to_color(color)==-1) {
2862    owl_function_error("No color named '%s' avilable.");
2863    return;
2864  }
2865  owl_filter_set_color(f, owl_util_string_to_color(color));
2866  owl_global_set_needrefresh(&g);
2867  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2868}
2869
2870void owl_function_show_colors()
2871{
2872  owl_fmtext fm;
2873
2874  owl_fmtext_init_null(&fm);
2875  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2876  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2877  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2878  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2879  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2880  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2881  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2882  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2883
2884  owl_function_popless_fmtext(&fm);
2885  owl_fmtext_free(&fm);
2886}
2887
2888/* add the given class, inst, recip to the punt list for filtering.
2889 *   if direction==0 then punt
2890 *   if direction==1 then unpunt
2891 */
2892void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2893{
2894  owl_filter *f;
2895  owl_list *fl;
2896  char *buff;
2897  char *quoted;
2898  int ret, i, j;
2899
2900  fl=owl_global_get_puntlist(&g);
2901
2902  /* first, create the filter */
2903  f=malloc(sizeof(owl_filter));
2904  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2905  strcpy(buff, "class");
2906  if (!strcmp(class, "*")) {
2907    strcat(buff, " .*");
2908  } else {
2909    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2910    owl_text_tr(quoted, ' ', '.');
2911    sprintf(buff, "%s ^%s$", buff, quoted);
2912    owl_free(quoted);
2913  }
2914  if (!strcmp(inst, "*")) {
2915    strcat(buff, " and instance .*");
2916  } else {
2917    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2918    owl_text_tr(quoted, ' ', '.');
2919    sprintf(buff, "%s and instance ^%s$", buff, quoted);
2920    owl_free(quoted);
2921  }
2922  if (strcmp(recip, "*")) {
2923    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2924    owl_text_tr(quoted, ' ', '.');
2925    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
2926    owl_free(quoted);
2927  }
2928 
2929  owl_function_debugmsg("About to filter %s", buff);
2930  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2931  owl_free(buff);
2932  if (ret) {
2933    owl_function_error("Error creating filter for zpunt");
2934    owl_filter_free(f);
2935    return;
2936  }
2937
2938  /* Check for an identical filter */
2939  j=owl_list_get_size(fl);
2940  for (i=0; i<j; i++) {
2941    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2942      /* if we're punting, then just silently bow out on this duplicate */
2943      if (direction==0) {
2944        owl_filter_free(f);
2945        return;
2946      }
2947
2948      /* if we're unpunting, then remove this filter from the puntlist */
2949      if (direction==1) {
2950        owl_filter_free(owl_list_get_element(fl, i));
2951        owl_list_remove_element(fl, i);
2952        return;
2953      }
2954    }
2955  }
2956
2957  /* If we're punting, add the filter to the global punt list */
2958  if (direction==0) {
2959    owl_list_append_element(fl, f);
2960  }
2961}
2962
2963void owl_function_activate_keymap(char *keymap)
2964{
2965  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2966    owl_function_error("Unable to activate keymap '%s'", keymap);
2967  }
2968}
2969
2970void owl_function_show_keymaps()
2971{
2972  owl_list l;
2973  owl_fmtext fm;
2974  owl_keymap *km;
2975  owl_keyhandler *kh;
2976  int i, numkm;
2977  char *kmname;
2978
2979  kh = owl_global_get_keyhandler(&g);
2980  owl_fmtext_init_null(&fm);
2981  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2982  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2983  owl_keyhandler_get_keymap_names(kh, &l);
2984  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2985  owl_fmtext_append_normal(&fm, "\n");
2986
2987  numkm = owl_list_get_size(&l);
2988  for (i=0; i<numkm; i++) {
2989    kmname = owl_list_get_element(&l, i);
2990    km = owl_keyhandler_get_keymap(kh, kmname);
2991    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2992    owl_keymap_get_details(km, &fm);   
2993  }
2994  owl_fmtext_append_normal(&fm, "\n");
2995 
2996  owl_function_popless_fmtext(&fm);
2997  owl_keyhandler_keymap_namelist_free(&l);
2998  owl_fmtext_free(&fm);
2999}
3000
3001char *owl_function_keymap_summary(void *name)
3002{
3003  owl_keymap *km
3004    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3005  if (km) return owl_keymap_summary(km);
3006  else return(NULL);
3007}
3008
3009/* TODO: implement for real */
3010void owl_function_show_keymap(char *name)
3011{
3012  owl_fmtext fm;
3013  owl_keymap *km;
3014
3015  owl_fmtext_init_null(&fm);
3016  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3017  if (km) {
3018    owl_keymap_get_details(km, &fm);
3019  } else {
3020    owl_fmtext_append_normal(&fm, "No such keymap...\n");
3021  } 
3022  owl_function_popless_fmtext(&fm);
3023  owl_fmtext_free(&fm);
3024}
3025
3026void owl_function_help_for_command(char *cmdname)
3027{
3028  owl_fmtext fm;
3029
3030  owl_fmtext_init_null(&fm);
3031  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3032  owl_function_popless_fmtext(&fm); 
3033  owl_fmtext_free(&fm);
3034}
3035
3036void owl_function_search_start(char *string, int direction)
3037{
3038  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3039  owl_global_set_search_active(&g, string);
3040  owl_function_search_helper(0, direction);
3041}
3042
3043void owl_function_search_continue(int direction)
3044{
3045  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3046  owl_function_search_helper(1, direction);
3047}
3048
3049void owl_function_search_helper(int mode, int direction)
3050{
3051  /* move to a message that contains the string.  If direction is
3052   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3053   * OWL_DIRECTION_UPWARDS then search backwards.
3054   *
3055   * If mode==0 then it will stay on the current message if it
3056   * contains the string.
3057   */
3058
3059  owl_view *v;
3060  int viewsize, i, curmsg, start;
3061  owl_message *m;
3062
3063  v=owl_global_get_current_view(&g);
3064  viewsize=owl_view_get_size(v);
3065  curmsg=owl_global_get_curmsg(&g);
3066 
3067  if (viewsize==0) {
3068    owl_function_error("No messages present");
3069    return;
3070  }
3071
3072  if (mode==0) {
3073    start=curmsg;
3074  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3075    start=curmsg+1;
3076  } else {
3077    start=curmsg-1;
3078  }
3079
3080  /* bounds check */
3081  if (start>=viewsize || start<0) {
3082    owl_function_error("No further matches found");
3083    return;
3084  }
3085
3086  for (i=start; i<viewsize && i>=0;) {
3087    m=owl_view_get_element(v, i);
3088    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3089      owl_global_set_curmsg(&g, i);
3090      owl_function_calculate_topmsg(direction);
3091      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3092      if (direction==OWL_DIRECTION_DOWNWARDS) {
3093        owl_global_set_direction_downwards(&g);
3094      } else {
3095        owl_global_set_direction_upwards(&g);
3096      }
3097      return;
3098    }
3099    if (direction==OWL_DIRECTION_DOWNWARDS) {
3100      i++;
3101    } else {
3102      i--;
3103    }
3104  }
3105  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3106  owl_function_error("No matches found");
3107}
3108
3109/* strips formatting from ztext and returns the unformatted text.
3110 * caller is responsible for freeing. */
3111char *owl_function_ztext_stylestrip(char *zt)
3112{
3113  owl_fmtext fm;
3114  char *plaintext;
3115
3116  owl_fmtext_init_null(&fm);
3117  owl_fmtext_append_ztext(&fm, zt);
3118  plaintext = owl_fmtext_print_plain(&fm);
3119  owl_fmtext_free(&fm);
3120  return(plaintext);
3121}
3122
3123/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3124void owl_function_buddylist(int aim, int zephyr, char *filename)
3125{
3126  int i, j, x, idle;
3127  owl_fmtext fm;
3128  owl_buddylist *bl;
3129  owl_buddy *b;
3130  owl_list anyone;
3131  char *foo, *timestr;
3132#ifdef HAVE_LIBZEPHYR
3133  char *tmp, *user, *line;
3134  ZLocations_t location[200];
3135  int numlocs, ret;
3136#endif
3137
3138  owl_fmtext_init_null(&fm);
3139
3140  /* AIM first */
3141  if (aim && owl_global_is_aimloggedin(&g)) {
3142    bl=owl_global_get_buddylist(&g);
3143
3144    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3145    /* we're assuming AIM for now */
3146    j=owl_buddylist_get_size(bl);
3147    for (i=0; i<j; i++) {
3148      b=owl_buddylist_get_buddy_n(bl, i);
3149      idle=owl_buddy_get_idle_time(b);
3150      if (idle!=0) {
3151        timestr=owl_util_minutes_to_timestr(idle);
3152      } else {
3153        timestr=owl_strdup("");
3154      }
3155      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3156      owl_fmtext_append_normal(&fm, foo);
3157      owl_free(timestr);
3158      owl_free(foo);
3159    }
3160  }
3161
3162#ifdef HAVE_LIBZEPHYR
3163  if (zephyr) {
3164    owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3165    owl_list_create(&anyone);
3166    ret=owl_zephyr_get_anyone_list(&anyone, filename);
3167    if (ret) {
3168      owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3169    } else {
3170      j=owl_list_get_size(&anyone);
3171      for (i=0; i<j; i++) {
3172        user=owl_list_get_element(&anyone, i);
3173        ret=ZLocateUser(user, &numlocs, ZAUTH);
3174        if (ret!=ZERR_NONE) {
3175          owl_function_error("Error getting location for %s", user);
3176          continue;
3177        }
3178       
3179        numlocs=200;
3180        ret=ZGetLocations(location, &numlocs);
3181        if (ret==0) {
3182          for (x=0; x<numlocs; x++) {
3183            line=malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3184            tmp=short_zuser(user);
3185            sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3186                    tmp,
3187                    location[x].host,
3188                    location[x].tty,
3189                    location[x].time);
3190            owl_fmtext_append_normal(&fm, line);
3191            owl_free(tmp);
3192          }
3193          if (numlocs>=200) {
3194            owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3195          }
3196        }
3197      }
3198    }
3199    owl_list_free_all(&anyone, owl_free);
3200  }
3201#endif
3202 
3203  owl_function_popless_fmtext(&fm);
3204  owl_fmtext_free(&fm);
3205}
3206
3207/* Dump messages in the current view to the file 'filename'. */
3208void owl_function_dump(char *filename) 
3209{
3210  int i, j, count;
3211  owl_message *m;
3212  owl_view *v;
3213  FILE *file;
3214
3215  v=owl_global_get_current_view(&g);
3216
3217  /* in the future make it ask yes/no */
3218  /*
3219  ret=stat(filename, &sbuf);
3220  if (!ret) {
3221    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3222    if (!ret) return;
3223  }
3224  */
3225
3226  file=fopen(filename, "w");
3227  if (!file) {
3228    owl_function_error("Error opening file");
3229    return;
3230  }
3231
3232  count=0;
3233  j=owl_view_get_size(v);
3234  for (i=0; i<j; i++) {
3235    m=owl_view_get_element(v, i);
3236    fputs(owl_message_get_text(m), file);
3237  }
3238  fclose(file);
3239  owl_function_makemsg("Messages dumped to %s", filename);
3240}
3241
3242void owl_function_do_newmsgproc(void)
3243{
3244  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3245    /* if there's a process out there, we need to check on it */
3246    if (owl_global_get_newmsgproc_pid(&g)) {
3247      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3248      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3249      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3250      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3251        /* it exited */
3252        owl_global_set_newmsgproc_pid(&g, 0);
3253        owl_function_debugmsg("newmsgproc exited");
3254      } else {
3255        owl_function_debugmsg("newmsgproc did not exit");
3256      }
3257    }
3258   
3259    /* if it exited, fork & exec a new one */
3260    if (owl_global_get_newmsgproc_pid(&g)==0) {
3261      int i, myargc;
3262      i=fork();
3263      if (i) {
3264        /* parent set the child's pid */
3265        owl_global_set_newmsgproc_pid(&g, i);
3266        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3267      } else {
3268        /* child exec's the program */
3269        char **parsed;
3270        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3271        if (myargc < 0) {
3272          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3273        }
3274        if (myargc <= 0) {
3275          _exit(127);
3276        }
3277        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3278        parsed[myargc] = NULL;
3279       
3280        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3281       
3282        execvp(parsed[0], parsed);
3283       
3284       
3285        /* was there an error exec'ing? */
3286        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3287                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3288        _exit(127);
3289      }
3290    }
3291  }
3292}
3293
3294/* print the xterm escape sequence to raise the window */
3295void owl_function_xterm_raise(void)
3296{
3297  printf("\033[5t");
3298}
3299
3300/* print the xterm escape sequence to deiconify the window */
3301void owl_function_xterm_deiconify(void)
3302{
3303  printf("\033[1t");
3304}
3305
3306/* Add the specified command to the startup file.  Eventually this
3307 * should be clever, and rewriting settings that will obviosly
3308 * override earlier settings with 'set' 'bindkey' and 'alias'
3309 * commands.  For now though we just remove any line that would
3310 * duplicate this one and then append this line to the end of
3311 * startupfile.
3312 */
3313void owl_function_addstartup(char *buff)
3314{
3315  FILE *file;
3316  char *filename;
3317
3318  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3319  file=fopen(filename, "a");
3320  if (!file) {
3321    owl_function_error("Error opening startupfile for new command");
3322    owl_free(filename);
3323    return;
3324  }
3325
3326  /* delete earlier copies */
3327  owl_util_file_deleteline(filename, buff, 1);
3328  owl_free(filename);
3329
3330  /* add this line */
3331  fprintf(file, "%s\n", buff);
3332
3333  fclose(file);
3334}
3335
3336/* Remove the specified command from the startup file. */
3337void owl_function_delstartup(char *buff)
3338{
3339  char *filename;
3340  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3341  owl_util_file_deleteline(filename, buff, 1);
3342  owl_free(filename);
3343}
3344
3345/* Execute owl commands from the given filename.  If the filename
3346 * is NULL, use the default owl startup commands file.
3347 */
3348void owl_function_source(char *filename)
3349{
3350  FILE *file;
3351  char buff[LINE];
3352
3353  if (!filename) {
3354    filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3355    file=fopen(filename, "r");
3356    owl_free(filename);
3357  } else {
3358    file=fopen(filename, "r");
3359  }
3360  if (!file) {
3361    /* just fail silently if it doesn't exist */
3362    return;
3363  }
3364  while (fgets(buff, LINE, file)!=NULL) {
3365    buff[strlen(buff)-1]='\0';
3366    owl_function_command(buff);
3367  }
3368  fclose(file);
3369}
3370
3371void owl_function_change_style(owl_view *v, char *stylename)
3372{
3373  owl_style *s;
3374
3375  s=owl_global_get_style_by_name(&g, stylename);
3376  if (!s) {
3377    owl_function_error("No style named %s", stylename);
3378    return;
3379  }
3380  owl_view_set_style(v, s);
3381  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3382  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3383  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3384}
3385
3386void owl_function_toggleoneline()
3387{
3388  owl_view *v;
3389  owl_style *s;
3390
3391  v=owl_global_get_current_view(&g);
3392  s=owl_view_get_style(v);
3393
3394  if (!owl_style_matches_name(s, "oneline")) {
3395    owl_function_change_style(v, "oneline");
3396  } else {
3397    owl_function_change_style(v, owl_global_get_default_style(&g));
3398  }
3399
3400  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3401  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3402  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3403}
3404
3405void owl_function_error(char *fmt, ...)
3406{
3407  va_list ap;
3408  char buff[2048], buff2[2048];
3409  char *date;
3410  time_t now;
3411
3412  now=time(NULL);
3413  date=owl_strdup(ctime(&now));
3414  date[strlen(date)-1]='\0';
3415
3416  va_start(ap, fmt);
3417
3418  vsnprintf(buff, 2048, fmt, ap);
3419  sprintf(buff2, "%s %s", date, buff);
3420  owl_function_debugmsg("ERROR: %s", buff);
3421  if (owl_global_get_curs_msgwin(&g)) {
3422    werase(owl_global_get_curs_msgwin(&g));
3423    waddstr(owl_global_get_curs_msgwin(&g), buff); 
3424    wnoutrefresh(owl_global_get_curs_msgwin(&g));
3425    owl_global_set_needrefresh(&g);
3426  }
3427  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3428  va_end(ap);
3429  owl_free(date);
3430}
3431
3432void owl_function_showerrs()
3433{
3434  owl_fmtext fm;
3435
3436  owl_fmtext_init_null(&fm);
3437  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3438  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3439  owl_function_popless_fmtext(&fm);
3440}
3441
3442void owl_function_makemsg(char *fmt, ...)
3443{
3444  va_list ap;
3445  char buff[2048];
3446
3447  if (!owl_global_get_curs_msgwin(&g)) return;
3448
3449  va_start(ap, fmt);
3450  werase(owl_global_get_curs_msgwin(&g));
3451 
3452  vsnprintf(buff, 2048, fmt, ap);
3453  owl_function_debugmsg("makemsg: %s", buff);
3454  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3455  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3456  owl_global_set_needrefresh(&g);
3457  va_end(ap);
3458}
3459
3460/* get locations for everyone in .anyone.  If 'notify' is '1' then
3461 * send a pseudo login or logout message for everyone not in sync with
3462 * the global zephyr buddy list.  The list is updated regardless of
3463 * the status of 'notify'.
3464 */
3465void owl_function_zephyr_buddy_check(int notify)
3466{
3467#ifdef HAVE_LIBZEPHYR
3468  int i, j;
3469  owl_list anyone;
3470  owl_message *m;
3471  owl_zbuddylist *zbl;
3472  char *user;
3473  ZLocations_t location[200];
3474  int numlocs, ret;
3475
3476  zbl=owl_global_get_zephyr_buddylist(&g);
3477
3478  owl_list_create(&anyone);
3479  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3480
3481  j=owl_list_get_size(&anyone);
3482  for (i=0; i<j; i++) {
3483    user=owl_list_get_element(&anyone, i);
3484    ret=ZLocateUser(user, &numlocs, ZAUTH);
3485    if (ret!=ZERR_NONE) {
3486      owl_function_error("Error getting location for %s", user);
3487      continue;
3488    }
3489    numlocs=200;
3490    ret=ZGetLocations(location, &numlocs);
3491    if (ret==0) {
3492      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3493        /* Send a PSEUDO LOGIN! */
3494        if (notify) {
3495          m=owl_malloc(sizeof(owl_message));
3496          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3497          owl_global_messagequeue_addmsg(&g, m);
3498        }
3499        owl_zbuddylist_adduser(zbl, user);
3500        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3501      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3502        /* I don't think this ever happens (if there are 0 locations we should get an error from
3503         * ZGetLocations)
3504         */
3505        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3506      }
3507    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3508      /* Send a PSEUDO LOGOUT! */
3509      if (notify) {
3510        m=owl_malloc(sizeof(owl_message));
3511        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3512        owl_global_messagequeue_addmsg(&g, m);
3513      }
3514      owl_zbuddylist_deluser(zbl, user);
3515      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3516    }
3517  }
3518
3519  owl_list_free_all(&anyone, owl_free);
3520#endif
3521}
3522
3523void owl_function_aimsearch_results(char *email, owl_list *namelist)
3524{
3525  owl_fmtext fm;
3526  int i, j;
3527
3528  owl_fmtext_init_null(&fm);
3529  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3530  owl_fmtext_append_normal(&fm, email);
3531  owl_fmtext_append_normal(&fm, ":\n");
3532
3533  j=owl_list_get_size(namelist);
3534  for (i=0; i<j; i++) {
3535    owl_fmtext_append_normal(&fm, "  ");
3536    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3537    owl_fmtext_append_normal(&fm, "\n");
3538  }
3539
3540  owl_function_popless_fmtext(&fm);
3541  owl_fmtext_free(&fm);
3542}
Note: See TracBrowser for help on using the repository browser.