source: functions.c @ 15b34fd

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