source: functions.c @ 8232149

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