source: functions.c @ f1cbb7a

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