source: perlconfig.c @ defe4a3

release-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since defe4a3 was f12d199, checked in by Geoffrey Thomas <geofft@mit.edu>, 15 years ago
Revert "owl_function_info: Explain the auth status better." Unfortunately this code breaks if not HAVE_LIBZEPHYR. This reverts commit 2c14f4049d15e5dff469ded00dfd28a0947b423e.
  • Property mode set to 100644
File size: 13.6 KB
RevLine 
[f1e629d]1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <errno.h>
[908e388]7#define OWL_PERL
[f1e629d]8#include "owl.h"
9
[8203afd]10extern XS(boot_BarnOwl);
[908e388]11extern XS(boot_DynaLoader);
[af1920fd]12/* extern XS(boot_DBI); */
[f1e629d]13
[c3acb0b]14static void owl_perl_xs_init(pTHX)
15{
[f1e629d]16  char *file = __FILE__;
17  dXSUB_SYS;
18  {
[8203afd]19    newXS("BarnOwl::bootstrap", boot_BarnOwl, file);
[908e388]20    newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
[f1e629d]21  }
22}
23
[30678ae]24SV *owl_perlconfig_message2hashref(owl_message *m)
[c3acb0b]25{
[1cc95709]26  HV *h, *stash;
[f1e629d]27  SV *hr;
[30678ae]28  char *ptr, *blessas, *type;
[b0430a6]29  int i, j;
[421c8ef7]30  owl_pair *pair;
[f6b319c]31  owl_filter *wrap;
[f1e629d]32
33  if (!m) return &PL_sv_undef;
[f6b319c]34  wrap = owl_global_get_filter(&g, "wordwrap");
35  if(!wrap) {
36      owl_function_error("wrap filter is not defined");
37      return &PL_sv_undef;
38  }
39
[f1e629d]40  h = newHV();
41
[3ea31b6]42#define MSG2H(h,field) (void)hv_store(h, #field, strlen(#field),        \
43                                      newSVpv(owl_message_get_##field(m),0), 0)
[f1e629d]44
45  if (owl_message_is_type_zephyr(m)
46      && owl_message_is_direction_in(m)) {
47    /* Handle zephyr-specific fields... */
48    AV *av_zfields;
49
50    av_zfields = newAV();
51    j=owl_zephyr_get_num_fields(owl_message_get_notice(m));
52    for (i=0; i<j; i++) {
[5376a95]53      ptr=owl_zephyr_get_field_as_utf8(owl_message_get_notice(m), i+1);
[b0430a6]54      av_push(av_zfields, newSVpvn(ptr, strlen(ptr)));
55      owl_free(ptr);
[f1e629d]56    }
[3ea31b6]57    (void)hv_store(h, "fields", strlen("fields"), newRV_noinc((SV*)av_zfields), 0);
[f1e629d]58
[3ea31b6]59    (void)hv_store(h, "auth", strlen("auth"), 
[f12d199]60                   newSVpv(owl_zephyr_get_authstr(owl_message_get_notice(m)),0),0);
[f1e629d]61  }
62
[421c8ef7]63  j=owl_list_get_size(&(m->attributes));
64  for(i=0; i<j; i++) {
65    pair=owl_list_get_element(&(m->attributes), i);
[3ea31b6]66    (void)hv_store(h, owl_pair_get_key(pair), strlen(owl_pair_get_key(pair)),
67                   newSVpv(owl_pair_get_value(pair),0),0);
[421c8ef7]68  }
69 
[f1e629d]70  MSG2H(h, type);
71  MSG2H(h, direction);
72  MSG2H(h, class);
73  MSG2H(h, instance);
74  MSG2H(h, sender);
75  MSG2H(h, realm);
76  MSG2H(h, recipient);
77  MSG2H(h, opcode);
78  MSG2H(h, hostname);
79  MSG2H(h, body);
80  MSG2H(h, login);
81  MSG2H(h, zsig);
82  MSG2H(h, zwriteline);
83  if (owl_message_get_header(m)) {
84    MSG2H(h, header); 
85  }
[3ea31b6]86  (void)hv_store(h, "time", strlen("time"), newSVpv(owl_message_get_timestr(m),0),0);
[d1ae4a4]87  (void)hv_store(h, "unix_time", strlen("unix_time"), newSViv(m->time), 0);
[3ea31b6]88  (void)hv_store(h, "id", strlen("id"), newSViv(owl_message_get_id(m)),0);
89  (void)hv_store(h, "deleted", strlen("deleted"), newSViv(owl_message_is_delete(m)),0);
90  (void)hv_store(h, "private", strlen("private"), newSViv(owl_message_is_private(m)),0);
91  (void)hv_store(h, "should_wordwrap",
92                 strlen("should_wordwrap"), newSViv(
93                                                    owl_filter_message_match(wrap, m)),0);
[f1e629d]94
[30678ae]95  type = owl_message_get_type(m);
[8fba2ee]96  if(!type || !*type) type = "generic";
[30678ae]97  type = owl_strdup(type);
98  type[0] = toupper(type[0]);
99  blessas = owl_sprintf("BarnOwl::Message::%s", type);
[f1e629d]100
[19bab8e]101  hr = newRV_noinc((SV*)h);
[1cc95709]102  stash =  gv_stashpv(blessas,0);
103  if(!stash) {
104    owl_function_error("No such class: %s for message type %s", blessas, owl_message_get_type(m));
105    stash = gv_stashpv("BarnOwl::Message", 1);
106  }
107  hr = sv_bless(hr,stash);
[30678ae]108  owl_free(type);
109  owl_free(blessas);
110  return hr;
[f1e629d]111}
112
[c3acb0b]113SV *owl_perlconfig_curmessage2hashref(void) /*noproto*/
114{
[f1e629d]115  int curmsg;
116  owl_view *v;
117  v=owl_global_get_current_view(&g);
118  if (owl_view_get_size(v) < 1) {
119    return &PL_sv_undef;
120  }
121  curmsg=owl_global_get_curmsg(&g);
122  return owl_perlconfig_message2hashref(owl_view_get_element(v, curmsg));
123}
124
[30678ae]125/* XXX TODO: Messages should round-trip properly between
126   message2hashref and hashref2message. Currently we lose
127   zephyr-specific properties stored in the ZNotice_t
[87dfeb7]128
129   This has been somewhat addressed, but is still not lossless.
[30678ae]130 */
131owl_message * owl_perlconfig_hashref2message(SV *msg)
132{
133  owl_message * m;
134  HE * ent;
135  I32 count, len;
136  char *key,*val;
137  HV * hash;
[ad15610]138  struct tm tm;
[30678ae]139
140  hash = (HV*)SvRV(msg);
141
142  m = owl_malloc(sizeof(owl_message));
143  owl_message_init(m);
144
145  count = hv_iterinit(hash);
146  while((ent = hv_iternext(hash))) {
147    key = hv_iterkey(ent, &len);
148    val = SvPV_nolen(hv_iterval(hash, ent));
149    if(!strcmp(key, "type")) {
150      owl_message_set_type(m, val);
151    } else if(!strcmp(key, "direction")) {
152      owl_message_set_direction(m, owl_message_parse_direction(val));
153    } else if(!strcmp(key, "private")) {
154      SV * v = hv_iterval(hash, ent);
155      if(SvTRUE(v)) {
156        owl_message_set_isprivate(m);
157      }
158    } else if (!strcmp(key, "hostname")) {
159      owl_message_set_hostname(m, val);
160    } else if (!strcmp(key, "zwriteline")) {
161      owl_message_set_zwriteline(m, val);
162    } else if (!strcmp(key, "time")) {
163      m->timestr = owl_strdup(val);
164      strptime(val, "%a %b %d %T %Y", &tm);
165      m->time = mktime(&tm);
166    } else {
167      owl_message_set_attribute(m, key, val);
168    }
169  }
170  if(owl_message_is_type_admin(m)) {
171    if(!owl_message_get_attribute_value(m, "adminheader"))
172      owl_message_set_attribute(m, "adminheader", "");
173  }
[87dfeb7]174#ifdef HAVE_LIBZEPHYR
175  if (owl_message_is_type_zephyr(m)) {
176    ZNotice_t *n = &(m->notice);
177    n->z_kind = ACKED;
178    n->z_port = 0;
179    n->z_auth = ZAUTH_NO;
180    n->z_checked_auth = 0;
181    n->z_class = owl_message_get_class(m);
182    n->z_class_inst = owl_message_get_instance(m);
183    n->z_opcode = owl_message_get_opcode(m);
184    n->z_sender = owl_message_get_sender(m);
185    n->z_recipient = owl_message_get_recipient(m);
186    n->z_default_format = "[zephyr created from perl]";
187    n->z_multinotice = "[zephyr created from perl]";
188    n->z_num_other_fields = 0;
189    n->z_message = owl_sprintf("%s%c%s", owl_message_get_zsig(m), '\0', owl_message_get_body(m));
190    n->z_message_len = strlen(owl_message_get_zsig(m)) + strlen(owl_message_get_body(m)) + 1;
191  }
192#endif
[30678ae]193  return m;
194}
[f1e629d]195
196/* Calls in a scalar context, passing it a hash reference.
197   If return value is non-null, caller must free. */
[c3acb0b]198char *owl_perlconfig_call_with_message(char *subname, owl_message *m)
199{
[f1e629d]200  dSP ;
[c4ba74d]201  int count;
[f1e629d]202  SV *msgref, *srv;
[909771e]203  char *out;
[f1e629d]204 
205  ENTER ;
206  SAVETMPS;
207 
208  PUSHMARK(SP) ;
209  msgref = owl_perlconfig_message2hashref(m);
[19bab8e]210  XPUSHs(sv_2mortal(msgref));
[f1e629d]211  PUTBACK ;
212 
213  count = call_pv(subname, G_SCALAR|G_EVAL|G_KEEPERR);
214 
215  SPAGAIN ;
216
217  if (SvTRUE(ERRSV)) {
[ce6721f]218    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
[27c3a93]219    /* and clear the error */
220    sv_setsv (ERRSV, &PL_sv_undef);
[f1e629d]221  }
222
223  if (count != 1) {
224    fprintf(stderr, "bad perl!  no biscuit!  returned wrong count!\n");
225    abort();
226  }
227
228  srv = POPs;
229
230  if (srv) {
[909771e]231    out = owl_strdup(SvPV_nolen(srv));
[f1e629d]232  } else {
233    out = NULL;
234  }
235 
236  PUTBACK ;
237  FREETMPS ;
238  LEAVE ;
239
240  return out;
241}
242
[25729b2]243
244/* Calls a method on a perl object representing a message.
245   If the return value is non-null, the caller must free it.
246 */
247char * owl_perlconfig_message_call_method(owl_message *m, char *method, int argc, char ** argv)
248{
249  dSP;
[909771e]250  unsigned int count, i;
[25729b2]251  SV *msgref, *srv;
[909771e]252  char *out;
[25729b2]253
254  msgref = owl_perlconfig_message2hashref(m);
255
256  ENTER;
257  SAVETMPS;
258
259  PUSHMARK(SP);
[19bab8e]260  XPUSHs(sv_2mortal(msgref));
[25729b2]261  for(i=0;i<argc;i++) {
262    XPUSHs(sv_2mortal(newSVpv(argv[i], 0)));
263  }
264  PUTBACK;
265
266  count = call_method(method, G_SCALAR|G_KEEPERR|G_EVAL);
267
268  SPAGAIN;
269
270  if(count != 1) {
271    fprintf(stderr, "perl returned wrong count %d\n", count);
272    abort();
273  }
274
275  if (SvTRUE(ERRSV)) {
[ce6721f]276    owl_function_error("Error: '%s'", SvPV_nolen(ERRSV));
[25729b2]277    /* and clear the error */
278    sv_setsv (ERRSV, &PL_sv_undef);
279  }
280
281  srv = POPs;
282
283  if (srv) {
[909771e]284    out = owl_strdup(SvPV_nolen(srv));
[25729b2]285  } else {
286    out = NULL;
287  }
288
289  PUTBACK;
290  FREETMPS;
291  LEAVE;
292
293  return out;
294}
295
296
[e8c6d8f]297char *owl_perlconfig_initperl(char * file, int *Pargc, char ***Pargv, char *** Penv)
[c3acb0b]298{
[d03091c]299  int ret;
[f1e629d]300  PerlInterpreter *p;
[4e0f545]301  char *err;
[d03091c]302  char *args[4] = {"", "-e", "0;", NULL};
[fd8dfe7]303  AV *inc;
304  char *path;
[f1e629d]305
306  /* create and initialize interpreter */
[e8c6d8f]307  PERL_SYS_INIT3(Pargc, Pargv, Penv);
[f1e629d]308  p=perl_alloc();
[4d86e06]309  owl_global_set_perlinterp(&g, p);
[f1e629d]310  perl_construct(p);
311
312  owl_global_set_no_have_config(&g);
313
[d03091c]314  ret=perl_parse(p, owl_perl_xs_init, 2, args, NULL);
[f1e629d]315  if (ret || SvTRUE(ERRSV)) {
[ce6721f]316    err=owl_strdup(SvPV_nolen(ERRSV));
[4e0f545]317    sv_setsv(ERRSV, &PL_sv_undef);     /* and clear the error */
318    return(err);
[f1e629d]319  }
320
321  ret=perl_run(p);
322  if (ret || SvTRUE(ERRSV)) {
[ce6721f]323    err=owl_strdup(SvPV_nolen(ERRSV));
[4e0f545]324    sv_setsv(ERRSV, &PL_sv_undef);     /* and clear the error */
325    return(err);
[f1e629d]326  }
327
328  owl_global_set_have_config(&g);
329
330  /* create legacy variables */
[c415aca]331  get_sv("BarnOwl::id", TRUE);
332  get_sv("BarnOwl::class", TRUE);
333  get_sv("BarnOwl::instance", TRUE);
334  get_sv("BarnOwl::recipient", TRUE);
335  get_sv("BarnOwl::sender", TRUE);
336  get_sv("BarnOwl::realm", TRUE);
337  get_sv("BarnOwl::opcode", TRUE);
338  get_sv("BarnOwl::zsig", TRUE);
339  get_sv("BarnOwl::msg", TRUE);
340  get_sv("BarnOwl::time", TRUE);
341  get_sv("BarnOwl::host", TRUE);
342  get_av("BarnOwl::fields", TRUE);
[00f9a7d]343
344  if(file) {
[8203afd]345    SV * cfg = get_sv("BarnOwl::configfile", TRUE);
[00f9a7d]346    sv_setpv(cfg, file);
347  }
348
[fd8dfe7]349  /* Add the system lib path to @INC */
350  inc = get_av("INC", 0);
351  path = owl_sprintf("%s/lib", owl_get_datadir());
352  av_unshift(inc, 1);
353  av_store(inc, 0, newSVpv(path, 0));
354  owl_free(path);
355
356  eval_pv("use BarnOwl;", FALSE);
[f1e629d]357
358  if (SvTRUE(ERRSV)) {
[ce6721f]359    err=owl_strdup(SvPV_nolen(ERRSV));
[27c3a93]360    sv_setsv (ERRSV, &PL_sv_undef);     /* and clear the error */
[4e0f545]361    return(err);
[f1e629d]362  }
363
364  /* check if we have the formatting function */
[8203afd]365  if (owl_perlconfig_is_function("BarnOwl::format_msg")) {
[f1e629d]366    owl_global_set_config_format(&g, 1);
367  }
368
369  return(NULL);
370}
371
372/* returns whether or not a function exists */
373int owl_perlconfig_is_function(char *fn) {
[c415aca]374  if (get_cv(fn, FALSE)) return(1);
[f1e629d]375  else return(0);
376}
377
378/* caller is responsible for freeing returned string */
[c3acb0b]379char *owl_perlconfig_execute(char *line)
380{
[f1e629d]381  STRLEN len;
382  SV *response;
383  char *out, *preout;
384
385  if (!owl_global_have_config(&g)) return NULL;
386
[e0096b7]387  ENTER;
388  SAVETMPS;
[f1e629d]389  /* execute the subroutine */
[c415aca]390  response = eval_pv(line, FALSE);
[f1e629d]391
392  if (SvTRUE(ERRSV)) {
[ce6721f]393    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
[27c3a93]394    sv_setsv (ERRSV, &PL_sv_undef);     /* and clear the error */
[f1e629d]395  }
396
397  preout=SvPV(response, len);
[909771e]398  if (len == 0 || preout[len - 1] != '\n')
399    out = owl_sprintf("%s\n", preout);
400  else
401    out = owl_strdup(preout);
[e0096b7]402  FREETMPS;
403  LEAVE;
[f1e629d]404
405  return(out);
406}
407
[b67ab6b]408void owl_perlconfig_getmsg(owl_message *m, char *subname)
409{
410  char *ptr = NULL;
411  if (owl_perlconfig_is_function("BarnOwl::Hooks::_receive_msg")) {
412    ptr = owl_perlconfig_call_with_message(subname?subname
413                                           :"BarnOwl::_receive_msg_legacy_wrap", m);
[f1e629d]414  }
[b67ab6b]415  if (ptr) owl_free(ptr);
[0f9eca7]416}
417
418/* Called on all new messages; receivemsg is only called on incoming ones */
419void owl_perlconfig_newmsg(owl_message *m, char *subname)
420{
421  char *ptr = NULL;
422  if (owl_perlconfig_is_function("BarnOwl::Hooks::_new_msg")) {
423    ptr = owl_perlconfig_call_with_message(subname?subname
424                                           :"BarnOwl::Hooks::_new_msg", m);
425  }
426  if (ptr) owl_free(ptr);
[f1e629d]427}
[6922edd]428
[eb6cedc]429void owl_perlconfig_new_command(char *name)
430{
431  dSP;
432
433  ENTER;
434  SAVETMPS;
435
436  PUSHMARK(SP);
437  XPUSHs(sv_2mortal(newSVpv(name, 0)));
438  PUTBACK;
439
440  call_pv("BarnOwl::Hooks::_new_command", G_SCALAR|G_VOID);
441
442  SPAGAIN;
443
444  if(SvTRUE(ERRSV)) {
445    owl_function_error("%s", SvPV_nolen(ERRSV));
446  }
447
448  FREETMPS;
449  LEAVE;
450}
451
[6922edd]452char *owl_perlconfig_perlcmd(owl_cmd *cmd, int argc, char **argv)
453{
454  int i, count;
455  char * ret = NULL;
[ad15610]456  SV *rv;
[6922edd]457  dSP;
458
459  ENTER;
460  SAVETMPS;
461
462  PUSHMARK(SP);
463  for(i=0;i<argc;i++) {
[367fbf3]464    SV *tmp = newSVpv(argv[i], 0);
465    SvUTF8_on(tmp);
466    XPUSHs(sv_2mortal(tmp));
[6922edd]467  }
468  PUTBACK;
469
470  count = call_sv(cmd->cmd_perl, G_SCALAR|G_EVAL);
471
472  SPAGAIN;
473
474  if(SvTRUE(ERRSV)) {
[ce6721f]475    owl_function_error("%s", SvPV_nolen(ERRSV));
[c4ba74d]476    (void)POPs;
[6922edd]477  } else {
478    if(count != 1)
479      croak("Perl command %s returned more than one value!", cmd->name);
[ad15610]480    rv = POPs;
[6922edd]481    if(SvTRUE(rv)) {
[ce6721f]482      ret = owl_strdup(SvPV_nolen(rv));
[6922edd]483    }
484  }
485
486  FREETMPS;
487  LEAVE;
488
489  return ret;
490}
491
492void owl_perlconfig_cmd_free(owl_cmd *cmd)
493{
[ff13a6f]494  SvREFCNT_dec(cmd->cmd_perl);
[6922edd]495}
[db8b00b]496
[9c7a701]497void owl_perlconfig_dispatch_free(owl_dispatch *d)
498{
[4d86e06]499  SvREFCNT_dec(d->data);
[1895c29]500  owl_free(d);
[9c7a701]501}
502
[db8b00b]503void owl_perlconfig_edit_callback(owl_editwin *e)
504{
[4d86e06]505  SV *cb = owl_editwin_get_cbdata(e);
[367fbf3]506  SV *text;
[ad15610]507  dSP;
508
[db8b00b]509  if(cb == NULL) {
510    owl_function_error("Perl callback is NULL!");
511  }
[367fbf3]512  text = newSVpv(owl_editwin_get_text(e), 0);
513  SvUTF8_on(text);
[db8b00b]514
515  ENTER;
516  SAVETMPS;
517
518  PUSHMARK(SP);
[367fbf3]519  XPUSHs(sv_2mortal(text));
[db8b00b]520  PUTBACK;
521 
[9364a36]522  call_sv(cb, G_DISCARD|G_KEEPERR|G_EVAL);
523
524  if(SvTRUE(ERRSV)) {
[ce6721f]525    owl_function_error("%s", SvPV_nolen(ERRSV));
[9364a36]526  }
[db8b00b]527
528  FREETMPS;
529  LEAVE;
530
531  SvREFCNT_dec(cb);
[a556caa]532  owl_editwin_set_cbdata(e, NULL);
[db8b00b]533}
[f72f573]534
535void owl_perlconfig_mainloop()
536{
[ad15610]537  dSP;
[0337203]538  if (!owl_perlconfig_is_function("BarnOwl::Hooks::_mainloop_hook"))
[8203afd]539    return;
[f72f573]540  PUSHMARK(SP) ;
[0337203]541  call_pv("BarnOwl::Hooks::_mainloop_hook", G_DISCARD|G_EVAL);
[a55abb3]542  if(SvTRUE(ERRSV)) {
[ce6721f]543    owl_function_error("%s", SvPV_nolen(ERRSV));
[a55abb3]544  }
[f72f573]545  return;
546}
[9c7a701]547
[f36cd97]548void owl_perlconfig_dispatch(owl_dispatch *d)
[9c7a701]549{
[f36cd97]550  SV *cb = d->data;
[9c7a701]551  dSP;
552  if(cb == NULL) {
553    owl_function_error("Perl callback is NULL!");
[f36cd97]554    return;
[9c7a701]555  }
556
557  ENTER;
558  SAVETMPS;
559
560  PUSHMARK(SP);
561  PUTBACK;
562 
563  call_sv(cb, G_DISCARD|G_KEEPERR|G_EVAL);
564
565  if(SvTRUE(ERRSV)) {
[ce6721f]566    owl_function_error("%s", SvPV_nolen(ERRSV));
[9c7a701]567  }
568
569  FREETMPS;
570  LEAVE;
571}
[1631825]572
573void owl_perlconfig_perl_timer(owl_timer *t, void *data)
574{
575  SV *obj = data;
576
577  if(!SvROK(obj)) {
578    return;
579  }
580
581  dSP;
582  ENTER;
583  SAVETMPS;
584
585  PUSHMARK(SP);
586  XPUSHs(obj);
587  PUTBACK;
588
589  call_method("do_callback", G_DISCARD|G_KEEPERR|G_EVAL);
590
591  SPAGAIN;
592
593  if (SvTRUE(ERRSV)) {
594    owl_function_error("Error in calback: '%s'", SvPV_nolen(ERRSV));
595    sv_setsv (ERRSV, &PL_sv_undef);
596  }
597
598  PUTBACK;
599  FREETMPS;
600  LEAVE;
601}
602
603void owl_perlconfig_perl_timer_destroy(owl_timer *t)
604{
605  if(SvOK((SV*)t->data)) {
606    SvREFCNT_dec((SV*)t->data);
607  }
608}
Note: See TracBrowser for help on using the repository browser.