source: functions.c @ 4367915

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