source: zephyr.c @ 18105584

debianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 18105584 was 18105584, checked in by Nelson Elhage <nelhage@mit.edu>, 15 years ago
zephyr: Don't give bogus error messages when adding subscriptions. We were returning the value of an uninitalized 'ret' if we added subscriptions to the deferred list instead of taking them immediately. This primarily manifests as an occasional (false) error suscribing to login messages at startup.
  • Property mode set to 100644
File size: 30.3 KB
Line 
1#include <stdlib.h>
2#include <unistd.h>
3#include <sys/types.h>
4#include <sys/wait.h>
5#include <sys/stat.h>
6#include <string.h>
7#include "owl.h"
8
9static const char fileIdent[] = "$Id$";
10
11static GList *deferred_subs = NULL;
12typedef struct _owl_sub_list {                            /* noproto */
13  ZSubscription_t *subs;
14  int nsubs;
15} owl_sub_list;
16
17#ifdef HAVE_LIBZEPHYR
18Code_t ZResetAuthentication();
19#endif
20
21#define HM_SVC_FALLBACK         htons((unsigned short) 2104)
22
23#ifdef HAVE_LIBZEPHYR
24void owl_zephyr_initialize()
25{
26  int ret;
27  struct servent *sp;
28  struct sockaddr_in sin;
29  ZNotice_t req;
30  Code_t code;
31  owl_dispatch *dispatch;
32
33  /*
34   * Code modified from libzephyr's ZhmStat.c
35   *
36   * Modified to add the fd to our select loop, rather than hanging
37   * until we get an ack.
38   */
39
40  if ((ret = ZOpenPort(NULL)) != ZERR_NONE) {
41    owl_function_error("Error opening Zephyr port: %s", error_message(ret));
42    return;
43  }
44
45  (void) memset((char *)&sin, 0, sizeof(struct sockaddr_in));
46
47  sp = getservbyname(HM_SVCNAME, "udp");
48
49  sin.sin_port = (sp) ? sp->s_port : HM_SVC_FALLBACK;
50  sin.sin_family = AF_INET;
51
52  sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
53
54  (void) memset((char *)&req, 0, sizeof(req));
55  req.z_kind = STAT;
56  req.z_port = 0;
57  req.z_class = HM_STAT_CLASS;
58  req.z_class_inst = HM_STAT_CLIENT;
59  req.z_opcode = HM_GIMMESTATS;
60  req.z_sender = "";
61  req.z_recipient = "";
62  req.z_default_format = "";
63  req.z_message_len = 0;
64
65  if ((code = ZSetDestAddr(&sin)) != ZERR_NONE) {
66    owl_function_error("Initializing Zephyr: %s", error_message(code));
67    return;
68  }
69
70  if ((code = ZSendNotice(&req, ZNOAUTH)) != ZERR_NONE) {
71    owl_function_error("Initializing Zephyr: %s", error_message(code));
72    return;
73  }
74
75  dispatch = owl_malloc(sizeof(*dispatch));
76  dispatch->fd = ZGetFD();
77  dispatch->cfunc = owl_zephyr_finish_initialization;
78  dispatch->destroy = (void(*)(owl_dispatch*))owl_free;
79
80  owl_select_add_dispatch(dispatch);
81}
82
83void owl_zephyr_finish_initialization(owl_dispatch *d) {
84  Code_t code;
85
86  owl_select_remove_dispatch(d->fd);
87
88  ZClosePort();
89
90  if ((code = ZInitialize()) != ZERR_NONE) {
91    owl_function_error("Initializing Zephyr: %s", error_message(code));
92    return;
93  }
94
95  if ((code = ZOpenPort(NULL)) != ZERR_NONE) {
96    owl_function_error("Initializing Zephyr: %s", error_message(code));
97    return;
98  }
99
100  d = owl_malloc(sizeof(owl_dispatch));
101  d->fd = ZGetFD();
102  d->cfunc = &owl_zephyr_process_events;
103  d->destroy = NULL;
104  owl_select_add_dispatch(d);
105  owl_global_set_havezephyr(&g);
106
107  if(g.load_initial_subs) {
108    owl_zephyr_load_initial_subs();
109  }
110  while(deferred_subs != NULL) {
111    owl_sub_list *subs = deferred_subs->data;
112    owl_function_debugmsg("Loading %d deferred subs.", subs->nsubs);
113    owl_zephyr_loadsubs_helper(subs->subs, subs->nsubs);
114    deferred_subs = g_list_delete_link(deferred_subs, deferred_subs);
115    owl_free(subs);
116  }
117}
118
119void owl_zephyr_load_initial_subs() {
120  int ret, ret2;
121
122  owl_function_debugmsg("startup: loading initial zephyr subs");
123
124  /* load default subscriptions */
125  ret = owl_zephyr_loaddefaultsubs();
126
127  /* load subscriptions from subs file */
128  ret2 = owl_zephyr_loadsubs(NULL, 0);
129
130  if (ret || ret2) {
131    owl_function_error("Error loading zephyr subscriptions");
132  } else if (ret2!=-1) {
133    owl_global_add_userclue(&g, OWL_USERCLUE_CLASSES);
134  }
135
136  /* load login subscriptions */
137  if (owl_global_is_loginsubs(&g)) {
138    owl_function_debugmsg("startup: loading login subs");
139    owl_function_loadloginsubs(NULL);
140  }
141}
142#else
143void owl_zephyr_initialize()
144{
145}
146#endif
147
148
149int owl_zephyr_shutdown()
150{
151#ifdef HAVE_LIBZEPHYR
152  if(owl_global_is_havezephyr(&g)) {
153    unsuball();
154    ZClosePort();
155  }
156#endif
157  return(0);
158}
159
160int owl_zephyr_zpending()
161{
162#ifdef HAVE_LIBZEPHYR
163  if(owl_global_is_havezephyr(&g))
164    return(ZPending());
165  else
166    return 0;
167#else
168  return(0);
169#endif
170}
171
172char *owl_zephyr_get_realm()
173{
174#ifdef HAVE_LIBZEPHYR
175  return(ZGetRealm());
176#else
177  return("");
178#endif
179}
180
181char *owl_zephyr_get_sender()
182{
183#ifdef HAVE_LIBZEPHYR
184  return(ZGetSender());
185#else
186  return("");
187#endif
188}
189
190#ifdef HAVE_LIBZEPHYR
191int owl_zephyr_loadsubs_helper(ZSubscription_t subs[], int count)
192{
193  int ret = 0;
194  if (owl_global_is_havezephyr(&g)) {
195    int i;
196    /* sub without defaults */
197    if (ZSubscribeToSansDefaults(subs,count,0) != ZERR_NONE) {
198      owl_function_error("Error subscribing to zephyr notifications.");
199      ret=-2;
200    }
201
202    /* free stuff */
203    for (i=0; i<count; i++) {
204      owl_free(subs[i].zsub_class);
205      owl_free(subs[i].zsub_classinst);
206      owl_free(subs[i].zsub_recipient);
207    }
208
209    owl_free(subs);
210  } else {
211    owl_sub_list *s = owl_malloc(sizeof(owl_sub_list));
212    s->subs = subs;
213    s->nsubs = count;
214    deferred_subs = g_list_append(deferred_subs, s);
215  }
216
217  return ret;
218}
219#endif
220
221/* Load zephyr subscriptions form 'filename'.  If 'filename' is NULL,
222 * the default file $HOME/.zephyr.subs will be used.
223 *
224 * Returns 0 on success.  If the file does not exist, return -1 if
225 * 'error_on_nofile' is 1, otherwise return 0.  Return -1 if the file
226 * exists but can not be read.  Return -2 if there is a failure from
227 * zephyr to load the subscriptions.
228 */
229int owl_zephyr_loadsubs(char *filename, int error_on_nofile)
230{
231#ifdef HAVE_LIBZEPHYR
232  FILE *file;
233  char *tmp, *start;
234  char buffer[1024], subsfile[1024];
235  ZSubscription_t *subs;
236  int subSize = 1024;
237  int count, ret;
238  struct stat statbuff;
239
240  subs = owl_malloc(sizeof(ZSubscription_t) * subSize);
241  if (filename==NULL) {
242    sprintf(subsfile, "%s/%s", owl_global_get_homedir(&g), ".zephyr.subs");
243  } else {
244    strcpy(subsfile, filename);
245  }
246
247  ret=stat(subsfile, &statbuff);
248  if (ret) {
249    if (error_on_nofile==1) return(-1);
250    return(0);
251  }
252
253  ZResetAuthentication();
254  count=0;
255  file=fopen(subsfile, "r");
256  if (!file) return(-1);
257  while ( fgets(buffer, 1024, file)!=NULL ) {
258    if (buffer[0]=='#' || buffer[0]=='\n' || buffer[0]=='\n') continue;
259   
260    if (buffer[0]=='-') {
261      start=buffer+1;
262    } else {
263      start=buffer;
264    }
265   
266    if (count >= subSize) {
267      subSize *= 2;
268      subs = owl_realloc(subs, sizeof(ZSubscription_t) * subSize);
269    }
270   
271    /* add it to the list of subs */
272    if ((tmp=(char *) strtok(start, ",\n\r"))==NULL) continue;
273    subs[count].zsub_class=owl_strdup(tmp);
274    if ((tmp=(char *) strtok(NULL, ",\n\r"))==NULL) continue;
275    subs[count].zsub_classinst=owl_strdup(tmp);
276    if ((tmp=(char *) strtok(NULL, " \t\n\r"))==NULL) continue;
277    subs[count].zsub_recipient=owl_strdup(tmp);
278   
279    /* if it started with '-' then add it to the global punt list, and
280     * remove it from the list of subs. */
281    if (buffer[0]=='-') {
282      owl_function_zpunt(subs[count].zsub_class, subs[count].zsub_classinst, subs[count].zsub_recipient, 0);
283      owl_free(subs[count].zsub_class);
284      owl_free(subs[count].zsub_classinst);
285      owl_free(subs[count].zsub_recipient);
286    }
287    else {
288      count++;
289    }
290  }
291  fclose(file);
292
293  owl_zephyr_loadsubs_helper(subs, count);
294  return(ret);
295#else
296  return(0);
297#endif
298}
299
300int owl_zephyr_loaddefaultsubs()
301{
302#ifdef HAVE_LIBZEPHYR
303  ZSubscription_t subs[10];
304   
305  if (ZSubscribeTo(subs,0,0) != ZERR_NONE) {
306    owl_function_error("Error subscribing to default zephyr notifications.");
307    return(-1);
308  }
309  return(0);
310#else
311  return(0);
312#endif
313}
314
315int owl_zephyr_loadloginsubs(char *filename)
316{
317#ifdef HAVE_LIBZEPHYR
318  FILE *file;
319  ZSubscription_t *subs;
320  int numSubs = 100;
321  char subsfile[1024], buffer[1024];
322  int count, ret;
323  struct stat statbuff;
324
325  subs = owl_malloc(numSubs * sizeof(ZSubscription_t));
326
327  if (filename==NULL) {
328    sprintf(subsfile, "%s/%s", owl_global_get_homedir(&g), ".anyone");
329  } else {
330    strcpy(subsfile, filename);
331  }
332 
333  ret=stat(subsfile, &statbuff);
334  if (ret) return(0);
335
336  ret=0;
337
338  ZResetAuthentication();
339  count=0;
340  file=fopen(subsfile, "r");
341  if (file) {
342    while ( fgets(buffer, 1024, file)!=NULL ) {
343      if (buffer[0]=='#' || buffer[0]=='\n' || buffer[0]=='\n') continue;
344     
345      if (count == numSubs) {
346        numSubs *= 2;
347        subs = owl_realloc(subs, numSubs * sizeof(ZSubscription_t));
348      }
349
350      buffer[strlen(buffer)-1]='\0';
351      subs[count].zsub_class=owl_strdup("login");
352      subs[count].zsub_recipient=owl_strdup("*");
353      if (strchr(buffer, '@')) {
354        subs[count].zsub_classinst=owl_strdup(buffer);
355      } else {
356        subs[count].zsub_classinst=owl_sprintf("%s@%s", buffer, ZGetRealm());
357      }
358
359      count++;
360    }
361    fclose(file);
362  } else {
363    count=0;
364    ret=-1;
365  }
366
367  ret = owl_zephyr_loadsubs_helper(subs, count);
368  return(ret);
369#else
370  return(0);
371#endif
372}
373
374void unsuball()
375{
376#if HAVE_LIBZEPHYR
377  int ret;
378
379  ZResetAuthentication();
380  ret=ZCancelSubscriptions(0);
381  if (ret != ZERR_NONE) {
382    com_err("owl",ret,"while unsubscribing");
383  }
384#endif
385}
386
387int owl_zephyr_sub(char *class, char *inst, char *recip)
388{
389#ifdef HAVE_LIBZEPHYR
390  ZSubscription_t subs[5];
391
392  subs[0].zsub_class=class;
393  subs[0].zsub_classinst=inst;
394  subs[0].zsub_recipient=recip;
395
396  ZResetAuthentication();
397  if (ZSubscribeTo(subs,1,0) != ZERR_NONE) {
398    owl_function_error("Error subbing to <%s,%s,%s>", class, inst, recip);
399    return(-2);
400  }
401  return(0);
402#else
403  return(0);
404#endif
405}
406
407
408int owl_zephyr_unsub(char *class, char *inst, char *recip)
409{
410#ifdef HAVE_LIBZEPHYR
411  ZSubscription_t subs[5];
412
413  subs[0].zsub_class=class;
414  subs[0].zsub_classinst=inst;
415  subs[0].zsub_recipient=recip;
416
417  ZResetAuthentication();
418  if (ZUnsubscribeTo(subs,1,0) != ZERR_NONE) {
419    owl_function_error("Error unsubbing from <%s,%s,%s>", class, inst, recip);
420    return(-2);
421  }
422  return(0);
423#else
424  return(0);
425#endif
426}
427
428/* return a pointer to the data in the Jth field, (NULL terminated by
429 * definition).  Caller must free the return.
430 */
431#ifdef HAVE_LIBZEPHYR
432char *owl_zephyr_get_field(ZNotice_t *n, int j)
433{
434  int i, count, save;
435  char *out;
436
437  /* If there's no message here, just run along now */
438  if (n->z_message_len == 0)
439    return(owl_strdup(""));
440
441  count=save=0;
442  for (i=0; i<n->z_message_len; i++) {
443    if (n->z_message[i]=='\0') {
444      count++;
445      if (count==j) {
446        /* just found the end of the field we're looking for */
447        return(owl_strdup(n->z_message+save));
448      } else {
449        save=i+1;
450      }
451    }
452  }
453  /* catch the last field, which might not be null terminated */
454  if (count==j-1) {
455    out=owl_malloc(n->z_message_len-save+5);
456    memcpy(out, n->z_message+save, n->z_message_len-save);
457    out[n->z_message_len-save]='\0';
458    return(out);
459  }
460
461  return(owl_strdup(""));
462}
463
464char *owl_zephyr_get_field_as_utf8(ZNotice_t *n, int j)
465{
466  int i, count, save;
467
468  /* If there's no message here, just run along now */
469  if (n->z_message_len == 0)
470    return(owl_strdup(""));
471
472  count=save=0;
473  for (i = 0; i < n->z_message_len; i++) {
474    if (n->z_message[i]=='\0') {
475      count++;
476      if (count == j) {
477        /* just found the end of the field we're looking for */
478        return(owl_validate_or_convert(n->z_message + save));
479      } else {
480        save = i + 1;
481      }
482    }
483  }
484  /* catch the last field, which might not be null terminated */
485  if (count == j - 1) {
486    char *tmp, *out;
487    tmp = owl_malloc(n->z_message_len-save+5);
488    memcpy(tmp, n->z_message+save, n->z_message_len-save);
489    tmp[n->z_message_len-save]='\0';
490    out = owl_validate_or_convert(tmp);
491    owl_free(tmp);
492    return out;
493  }
494
495  return(owl_strdup(""));
496}
497#else
498char *owl_zephyr_get_field(void *n, int j)
499{
500  return(owl_strdup(""));
501}
502char *owl_zephyr_get_field_as_utf8(void *n, int j)
503{
504  return owl_zephyr_get_field(n, j);
505}
506#endif
507
508
509#ifdef HAVE_LIBZEPHYR
510int owl_zephyr_get_num_fields(ZNotice_t *n)
511{
512  int i, fields;
513
514  if(n->z_message_len == 0)
515    return 0;
516
517  fields=1;
518  for (i=0; i<n->z_message_len; i++) {
519    if (n->z_message[i]=='\0') fields++;
520  }
521 
522  return(fields);
523}
524#else
525int owl_zephyr_get_num_fields(void *n)
526{
527  return(0);
528}
529#endif
530
531#ifdef HAVE_LIBZEPHYR
532/* return a pointer to the message, place the message length in k
533 * caller must free the return
534 */
535char *owl_zephyr_get_message(ZNotice_t *n, owl_message *m)
536{
537  /* don't let ping messages have a body */
538  if (!strcasecmp(n->z_opcode, "ping")) {
539    return(owl_strdup(""));
540  }
541
542  /* deal with MIT NOC messages */
543  if (!strcasecmp(n->z_default_format, "@center(@bold(NOC Message))\n\n@bold(Sender:) $1 <$sender>\n@bold(Time:  ) $time\n\n@italic($opcode service on $instance $3.) $4\n")) {
544    char *msg, *field3, *field4;
545
546    field3 = owl_zephyr_get_field(n, 3);
547    field4 = owl_zephyr_get_field(n, 4);
548
549    msg = owl_sprintf("%s service on %s %s\n%s", n->z_opcode, n->z_class_inst, field3, field4);
550    owl_free(field3);
551    owl_free(field4);
552    if (msg) {
553      return msg;
554    }
555  }
556  /* deal with MIT Discuss messages */
557  else if (!strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4") ||
558           !strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3\nSubject: $4")) {
559    char *msg, *field1, *field2, *field3, *field4, *field5;
560   
561    field1 = owl_zephyr_get_field(n, 1);
562    field2 = owl_zephyr_get_field(n, 2);
563    field3 = owl_zephyr_get_field(n, 3);
564    field4 = owl_zephyr_get_field(n, 4);
565    field5 = owl_zephyr_get_field(n, 5);
566   
567    msg = owl_sprintf("New transaction [%s] entered in %s\nFrom: %s (%s)\nSubject: %s", field1, field2, field3, field5, field4);
568    owl_free(field1);
569    owl_free(field2);
570    owl_free(field3);
571    owl_free(field4);
572    owl_free(field5);
573    if (msg) {
574      return msg;
575    }
576  }
577  /* deal with MIT Moira messages */
578  else if (!strcasecmp(n->z_default_format, "MOIRA $instance on $fromhost:\n $message\n")) {
579    char *msg, *field1;
580   
581    field1 = owl_zephyr_get_field(n, 1);
582   
583    msg = owl_sprintf("MOIRA %s on %s: %s", n->z_class_inst, owl_message_get_hostname(m), field1);
584    owl_free(field1);
585    if (msg) {
586      return msg;
587    }
588  }
589
590  if (owl_zephyr_get_num_fields(n) == 1) {
591    return(owl_zephyr_get_field(n, 1));
592  }
593  else {
594    return(owl_zephyr_get_field(n, 2));
595  }
596}
597#endif
598
599#ifdef HAVE_LIBZEPHYR
600char *owl_zephyr_get_zsig(ZNotice_t *n, int *k)
601{
602  /* return a pointer to the zsig if there is one */
603
604  /* message length 0? No zsig */
605  if (n->z_message_len==0) {
606    *k=0;
607    return("");
608  }
609
610  /* If there's only one field, no zsig */
611  if (owl_zephyr_get_num_fields(n) == 1) {
612    *k=0;
613    return("");
614  }
615
616  /* Everything else is field 1 */
617  *k=strlen(n->z_message);
618  return(n->z_message);
619}
620#else
621char *owl_zephyr_get_zsig(void *n, int *k)
622{
623  return("");
624}
625#endif
626
627int send_zephyr(char *opcode, char *zsig, char *class, char *instance, char *recipient, char *message)
628{
629#ifdef HAVE_LIBZEPHYR
630  int ret;
631  ZNotice_t notice;
632   
633  memset(&notice, 0, sizeof(notice));
634
635  ZResetAuthentication();
636
637  if (!zsig) zsig="";
638 
639  notice.z_kind=ACKED;
640  notice.z_port=0;
641  notice.z_class=class;
642  notice.z_class_inst=instance;
643  notice.z_sender=NULL;
644  if (!strcmp(recipient, "*") || !strcmp(recipient, "@")) {
645    notice.z_recipient="";
646    if (*owl_global_get_zsender(&g))
647        notice.z_sender=owl_global_get_zsender(&g);
648  } else {
649    notice.z_recipient=recipient;
650  }
651  notice.z_default_format="Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\nFrom: @bold{$1 <$sender>}\n\n$2";
652  if (opcode) notice.z_opcode=opcode;
653
654  notice.z_message_len=strlen(zsig)+1+strlen(message);
655  notice.z_message=owl_malloc(notice.z_message_len+10);
656  strcpy(notice.z_message, zsig);
657  memcpy(notice.z_message+strlen(zsig)+1, message, strlen(message));
658
659  /* ret=ZSendNotice(&notice, ZAUTH); */
660  ret=ZSrvSendNotice(&notice, ZAUTH, send_zephyr_helper);
661 
662  /* free then check the return */
663  owl_free(notice.z_message);
664  ZFreeNotice(&notice);
665  if (ret!=ZERR_NONE) {
666    owl_function_error("Error sending zephyr");
667    return(ret);
668  }
669  return(0);
670#else
671  return(0);
672#endif
673}
674
675#ifdef HAVE_LIBZEPHYR
676Code_t send_zephyr_helper(ZNotice_t *notice, char *buf, int len, int wait)
677{
678  return(ZSendPacket(buf, len, 0));
679}
680#endif
681
682void send_ping(char *to)
683{
684#ifdef HAVE_LIBZEPHYR
685  send_zephyr("PING", "", "MESSAGE", "PERSONAL", to, "");
686#endif
687}
688
689#ifdef HAVE_LIBZEPHYR
690void owl_zephyr_handle_ack(ZNotice_t *retnotice)
691{
692  char *tmp;
693 
694  /* if it's an HMACK ignore it */
695  if (retnotice->z_kind == HMACK) return;
696
697  if (retnotice->z_kind == SERVNAK) {
698    owl_function_error("Authorization failure sending zephyr");
699  } else if ((retnotice->z_kind != SERVACK) || !retnotice->z_message_len) {
700    owl_function_error("Detected server failure while receiving acknowledgement");
701  } else if (!strcmp(retnotice->z_message, ZSRVACK_SENT)) {
702    if (!strcasecmp(retnotice->z_opcode, "ping")) {
703      return;
704    } else if (!strcasecmp(retnotice->z_class, "message") &&
705               !strcasecmp(retnotice->z_class_inst, "personal")) {
706      tmp=short_zuser(retnotice->z_recipient);
707      owl_function_makemsg("Message sent to %s.", tmp);
708      free(tmp);
709    } else {
710      owl_function_makemsg("Message sent to -c %s -i %s\n", retnotice->z_class, retnotice->z_class_inst);
711    }
712  } else if (!strcmp(retnotice->z_message, ZSRVACK_NOTSENT)) {
713    #define BUFFLEN 1024
714    if (retnotice->z_recipient == NULL
715        || *retnotice->z_recipient == 0
716        || *retnotice->z_recipient == '@') {
717      char buff[BUFFLEN];
718      owl_function_error("No one subscribed to class %s", retnotice->z_class);
719      snprintf(buff, BUFFLEN, "Could not send message to class %s: no one subscribed.\n", retnotice->z_class);
720      owl_function_adminmsg("", buff);
721    } else {
722      char buff[BUFFLEN];
723      tmp = short_zuser(retnotice->z_recipient);
724      owl_function_error("%s: Not logged in or subscribing.", tmp);
725      if(strcmp(retnotice->z_class, "message")) {
726        snprintf(buff, BUFFLEN,
727                 "Could not send message to %s: "
728                 "not logged in or subscribing to class %s, instance %s.\n", 
729                 tmp,
730                 retnotice->z_class,
731                 retnotice->z_class_inst);
732      } else {
733        snprintf(buff, BUFFLEN,
734                 "Could not send message to %s: "
735                 "not logged in or subscribing to messages.\n",
736                 tmp);
737      }
738      owl_function_adminmsg("", buff);
739      owl_log_outgoing_zephyr_error(tmp, buff);
740      owl_free(tmp);
741    }
742  } else {
743    owl_function_error("Internal error on ack (%s)", retnotice->z_message);
744  }
745}
746#else
747void owl_zephyr_handle_ack(void *retnotice)
748{
749}
750#endif
751
752#ifdef HAVE_LIBZEPHYR
753int owl_zephyr_notice_is_ack(ZNotice_t *n)
754{
755  if (n->z_kind == SERVNAK || n->z_kind == SERVACK || n->z_kind == HMACK) {
756    if (!strcasecmp(n->z_class, LOGIN_CLASS)) return(0);
757    return(1);
758  }
759  return(0);
760}
761#else
762int owl_zephyr_notice_is_ack(void *n)
763{
764  return(0);
765}
766#endif
767 
768void owl_zephyr_zaway(owl_message *m)
769{
770#ifdef HAVE_LIBZEPHYR
771  char *tmpbuff, *myuser, *to;
772  owl_message *mout;
773 
774  /* bail if it doesn't look like a message we should reply to.  Some
775   * of this defined by the way zaway(1) works
776   */
777  if (strcasecmp(owl_message_get_class(m), "message")) return;
778  if (strcasecmp(owl_message_get_recipient(m), ZGetSender())) return;
779  if (!strcasecmp(owl_message_get_sender(m), "")) return;
780  if (!strcasecmp(owl_message_get_opcode(m), "ping")) return;
781  if (!strcasecmp(owl_message_get_opcode(m), "auto")) return;
782  if (!strcasecmp(owl_message_get_zsig(m), "Automated reply:")) return;
783  if (!strcasecmp(owl_message_get_sender(m), ZGetSender())) return;
784  if (owl_message_get_attribute_value(m, "isauto")) return;
785
786  if (owl_global_is_smartstrip(&g)) {
787    to=owl_zephyr_smartstripped_user(owl_message_get_sender(m));
788  } else {
789    to=owl_strdup(owl_message_get_sender(m));
790  }
791
792  send_zephyr("",
793              "Automated reply:",
794              owl_message_get_class(m),
795              owl_message_get_instance(m),
796              to,
797              owl_global_get_zaway_msg(&g));
798
799  myuser=short_zuser(to);
800  if (!strcasecmp(owl_message_get_instance(m), "personal")) {
801    tmpbuff = owl_sprintf("zwrite %s", myuser);
802  } else {
803    tmpbuff = owl_sprintf("zwrite -i %s %s", owl_message_get_instance(m), myuser);
804  }
805  owl_free(myuser);
806  owl_free(to);
807
808  /* display the message as an admin message in the receive window */
809  mout=owl_function_make_outgoing_zephyr(owl_global_get_zaway_msg(&g), tmpbuff, "Automated reply:");
810  owl_global_messagequeue_addmsg(&g, mout);
811  owl_free(tmpbuff);
812#endif
813}
814
815#ifdef HAVE_LIBZEPHYR
816void owl_zephyr_hackaway_cr(ZNotice_t *n)
817{
818  /* replace \r's with ' '.  Gross-ish */
819  int i;
820
821  for (i=0; i<n->z_message_len; i++) {
822    if (n->z_message[i]=='\r') {
823      n->z_message[i]=' ';
824    }
825  }
826}
827#endif
828
829void owl_zephyr_zlocate(char *user, char *out, int auth)
830{
831#ifdef HAVE_LIBZEPHYR
832  int ret, numlocs;
833  int one = 1;
834  ZLocations_t locations;
835  char *myuser;
836 
837  strcpy(out, "");
838  ZResetAuthentication();
839  ret=ZLocateUser(user,&numlocs,auth?ZAUTH:ZNOAUTH);
840  if (ret != ZERR_NONE) {
841    sprintf(out, "Error locating user %s\n", user);
842    return;
843  }
844
845  if (numlocs==0) {
846    myuser=short_zuser(user);
847    sprintf(out, "%s: Hidden or not logged in\n", myuser);
848    owl_free(myuser);
849    return;
850  }
851   
852  for (;numlocs;numlocs--) {
853    ZGetLocations(&locations,&one);
854    myuser=short_zuser(user);
855    sprintf(out + strlen(out), "%s: %s\t%s\t%s\n", myuser,
856            locations.host ? locations.host : "?",
857            locations.tty ? locations.tty : "?",
858            locations.time ? locations.time : "?");
859    owl_free(myuser);
860  }
861#endif
862}
863
864void owl_zephyr_addsub(char *filename, char *class, char *inst, char *recip)
865{
866#ifdef HAVE_LIBZEPHYR
867  char *line, subsfile[LINE], buff[LINE];
868  FILE *file;
869
870  line=owl_zephyr_makesubline(class, inst, recip);
871
872  if (filename==NULL) {
873    sprintf(subsfile, "%s/%s", owl_global_get_homedir(&g), ".zephyr.subs");
874  } else {
875    strcpy(subsfile, filename);
876  }
877
878  /* if the file already exists, check to see if the sub is already there */
879  file=fopen(subsfile, "r");
880  if (file) {
881    while (fgets(buff, LINE, file)!=NULL) {
882      if (!strcasecmp(buff, line)) {
883        owl_function_error("Subscription already present in %s", subsfile);
884        owl_free(line);
885        fclose(file);
886        return;
887      }
888    }
889    fclose(file);
890  }
891
892  /* if we get here then we didn't find it */
893  file=fopen(subsfile, "a");
894  if (!file) {
895    owl_function_error("Error opening file %s for writing", subsfile);
896    owl_free(line);
897    return;
898  }
899  fputs(line, file);
900  fclose(file);
901  owl_function_makemsg("Subscription added");
902 
903  owl_free(line);
904#endif
905}
906
907void owl_zephyr_delsub(char *filename, char *class, char *inst, char *recip)
908{
909#ifdef HAVE_LIBZEPHYR
910  char *line, *subsfile;
911 
912  line=owl_zephyr_makesubline(class, inst, recip);
913  line[strlen(line)-1]='\0';
914
915  if (!filename) {
916    subsfile=owl_sprintf("%s/.zephyr.subs", owl_global_get_homedir(&g));
917  } else {
918    subsfile=owl_strdup(filename);
919  }
920 
921  owl_util_file_deleteline(subsfile, line, 1);
922  owl_free(subsfile);
923  owl_free(line);
924  owl_function_makemsg("Subscription removed");
925#endif
926}
927
928/* caller must free the return */
929char *owl_zephyr_makesubline(char *class, char *inst, char *recip)
930{
931  char *out;
932
933  out=owl_malloc(strlen(class)+strlen(inst)+strlen(recip)+30);
934  sprintf(out, "%s,%s,%s\n", class, inst, !strcmp(recip, "") ? "*" : recip);
935  return(out);
936}
937
938
939void owl_zephyr_zlog_in(void)
940{
941#ifdef HAVE_LIBZEPHYR
942  char *exposure, *eset;
943  int ret;
944
945  ZResetAuthentication();
946   
947  eset=EXPOSE_REALMVIS;
948  exposure=ZGetVariable("exposure");
949  if (exposure==NULL) {
950    eset=EXPOSE_REALMVIS;
951  } else if (!strcasecmp(exposure,EXPOSE_NONE)) {
952    eset = EXPOSE_NONE;
953  } else if (!strcasecmp(exposure,EXPOSE_OPSTAFF)) {
954    eset = EXPOSE_OPSTAFF;
955  } else if (!strcasecmp(exposure,EXPOSE_REALMVIS)) {
956    eset = EXPOSE_REALMVIS;
957  } else if (!strcasecmp(exposure,EXPOSE_REALMANN)) {
958    eset = EXPOSE_REALMANN;
959  } else if (!strcasecmp(exposure,EXPOSE_NETVIS)) {
960    eset = EXPOSE_NETVIS;
961  } else if (!strcasecmp(exposure,EXPOSE_NETANN)) {
962    eset = EXPOSE_NETANN;
963  }
964   
965  ret=ZSetLocation(eset);
966  if (ret != ZERR_NONE) {
967    /*
968      char buff[LINE];
969      sprintf(buff, "Error setting location: %s", error_message(ret));
970      owl_function_makemsg(buff);
971    */
972  }
973#endif
974}
975
976void owl_zephyr_zlog_out(void)
977{
978#ifdef HAVE_LIBZEPHYR
979  int ret;
980
981  ZResetAuthentication();
982  ret=ZUnsetLocation();
983  if (ret != ZERR_NONE) {
984    /*
985      char buff[LINE];
986      sprintf(buff, "Error unsetting location: %s", error_message(ret));
987      owl_function_makemsg(buff);
988    */
989  }
990#endif
991}
992
993void owl_zephyr_addbuddy(char *name)
994{
995  char *filename;
996  FILE *file;
997 
998  filename=owl_sprintf("%s/.anyone", owl_global_get_homedir(&g));
999  file=fopen(filename, "a");
1000  owl_free(filename);
1001  if (!file) {
1002    owl_function_error("Error opening zephyr buddy file for append");
1003    return;
1004  }
1005  fprintf(file, "%s\n", name);
1006  fclose(file);
1007}
1008
1009void owl_zephyr_delbuddy(char *name)
1010{
1011  char *filename;
1012
1013  filename=owl_sprintf("%s/.anyone", owl_global_get_homedir(&g));
1014  owl_util_file_deleteline(filename, name, 0);
1015  owl_free(filename);
1016}
1017
1018/* return auth string */
1019#ifdef HAVE_LIBZEPHYR
1020char *owl_zephyr_get_authstr(ZNotice_t *n)
1021{
1022
1023  if (!n) return("UNKNOWN");
1024
1025  if (n->z_auth == ZAUTH_FAILED) {
1026    return ("FAILED");
1027  } else if (n->z_auth == ZAUTH_NO) {
1028    return ("NO");
1029  } else if (n->z_auth == ZAUTH_YES) {
1030    return ("YES");
1031  } else {
1032    return ("UNKNOWN");
1033  }           
1034}
1035#else
1036char *owl_zephyr_get_authstr(void *n)
1037{
1038  return("");
1039}
1040#endif
1041
1042/* Returns a buffer of subscriptions or an error message.  Caller must
1043 * free the return.
1044 */
1045char *owl_zephyr_getsubs()
1046{
1047#ifdef HAVE_LIBZEPHYR
1048  int ret, num, i, one;
1049  int buffsize;
1050  ZSubscription_t sub;
1051  char *out;
1052  one=1;
1053
1054  ret=ZRetrieveSubscriptions(0, &num);
1055  if (ret==ZERR_TOOMANYSUBS) {
1056    return(owl_strdup("Zephyr: too many subscriptions\n"));
1057  } else if (ret || (num <= 0)) {
1058    return(owl_strdup("Zephyr: error retriving subscriptions\n"));
1059  }
1060
1061  buffsize = (num + 1) * 50;
1062  out=owl_malloc(buffsize);
1063  strcpy(out, "");
1064  for (i=0; i<num; i++) {
1065    if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
1066      owl_free(out);
1067      ZFlushSubscriptions();
1068      out=owl_strdup("Error while getting subscriptions\n");
1069      return(out);
1070    } else {
1071      int tmpbufflen;
1072      char *tmpbuff;
1073      tmpbuff = owl_sprintf("<%s,%s,%s>\n%s", sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient, out);
1074      tmpbufflen = strlen(tmpbuff) + 1;
1075      if (tmpbufflen > buffsize) {
1076        char *out2;
1077        buffsize = tmpbufflen * 2;
1078        out2 = owl_realloc(out, buffsize);
1079        if (out2 == NULL) {
1080          owl_free(out);
1081          owl_free(tmpbuff);
1082          ZFlushSubscriptions();
1083          out=owl_strdup("Realloc error while getting subscriptions\n");
1084          return(out);   
1085        }
1086        out = out2;
1087      }
1088      strcpy(out, tmpbuff);
1089      owl_free(tmpbuff);
1090    }
1091  }
1092
1093  ZFlushSubscriptions();
1094  return(out);
1095#else
1096  return(owl_strdup("Zephyr not available"));
1097#endif
1098}
1099
1100char *owl_zephyr_get_variable(char *var)
1101{
1102#ifdef HAVE_LIBZEPHYR
1103  return(ZGetVariable(var));
1104#else
1105  return("");
1106#endif
1107}
1108
1109void owl_zephyr_set_locationinfo(char *host, char *val)
1110{
1111#ifdef HAVE_LIBZEPHYR
1112  ZInitLocationInfo(host, val);
1113#endif
1114}
1115 
1116/* Strip a local realm fron the zephyr user name.
1117 * The caller must free the return
1118 */
1119char *short_zuser(char *in)
1120{
1121  char *out, *ptr;
1122
1123  out=owl_strdup(in);
1124  ptr=strchr(out, '@');
1125  if (ptr) {
1126    if (!strcasecmp(ptr+1, owl_zephyr_get_realm())) {
1127      *ptr='\0';
1128    }
1129  }
1130  return(out);
1131}
1132
1133/* Append a local realm to the zephyr user name if necessary.
1134 * The caller must free the return.
1135 */
1136char *long_zuser(char *in)
1137{
1138  if (strchr(in, '@')) {
1139    return(owl_strdup(in));
1140  }
1141  return(owl_sprintf("%s@%s", in, owl_zephyr_get_realm()));
1142}
1143
1144/* strip out the instance from a zsender's principal.  Preserves the
1145 * realm if present.  daemon.webzephyr is a special case.  The
1146 * caller must free the return
1147 */
1148char *owl_zephyr_smartstripped_user(char *in)
1149{
1150  char *ptr, *realm, *out;
1151
1152  out=owl_strdup(in);
1153
1154  /* bail immeaditly if we don't have to do any work */
1155  ptr=strchr(in, '.');
1156  if (!strchr(in, '/') && !ptr) {
1157    /* no '/' and no '.' */
1158    return(out);
1159  }
1160  if (ptr && strchr(in, '@') && (ptr > strchr(in, '@'))) {
1161    /* There's a '.' but it's in the realm */
1162    return(out);
1163  }
1164  if (!strncasecmp(in, OWL_WEBZEPHYR_PRINCIPAL, strlen(OWL_WEBZEPHYR_PRINCIPAL))) {
1165    return(out);
1166  }
1167
1168  /* remove the realm from ptr, but hold on to it */
1169  realm=strchr(out, '@');
1170  if (realm) realm[0]='\0';
1171
1172  /* strip */
1173  ptr=strchr(out, '.');
1174  if (!ptr) ptr=strchr(out, '/');
1175  ptr[0]='\0';
1176
1177  /* reattach the realm if we had one */
1178  if (realm) {
1179    strcat(out, "@");
1180    strcat(out, realm+1);
1181  }
1182
1183  return(out);
1184}
1185
1186/* read the list of users in 'filename' as a .anyone file, and put the
1187 * names of the zephyr users in the list 'in'.  If 'filename' is NULL,
1188 * use the default .anyone file in the users home directory.  Returns
1189 * -1 on failure, 0 on success.
1190 */
1191int owl_zephyr_get_anyone_list(owl_list *in, char *filename)
1192{
1193#ifdef HAVE_LIBZEPHYR
1194  char *ourfile, *tmp, buff[LINE];
1195  FILE *f;
1196
1197  if (filename==NULL) {
1198    tmp=owl_global_get_homedir(&g);
1199    ourfile=owl_sprintf("%s/.anyone", owl_global_get_homedir(&g));
1200  } else {
1201    ourfile=owl_strdup(filename);
1202  }
1203 
1204  f=fopen(ourfile, "r");
1205  if (!f) {
1206    owl_function_error("Error opening file %s: %s", ourfile, strerror(errno) ? strerror(errno) : "");
1207    owl_free(ourfile);
1208    return(-1);
1209  }
1210
1211  while (fgets(buff, LINE, f)!=NULL) {
1212    /* ignore comments, blank lines etc. */
1213    if (buff[0]=='#') continue;
1214    if (buff[0]=='\n') continue;
1215    if (buff[0]=='\0') continue;
1216   
1217    /* strip the \n */
1218    buff[strlen(buff)-1]='\0';
1219   
1220    /* ingore from # on */
1221    tmp=strchr(buff, '#');
1222    if (tmp) tmp[0]='\0';
1223   
1224    /* ingore from SPC */
1225    tmp=strchr(buff, ' ');
1226    if (tmp) tmp[0]='\0';
1227   
1228    /* stick on the local realm. */
1229    if (!strchr(buff, '@')) {
1230      strcat(buff, "@");
1231      strcat(buff, ZGetRealm());
1232    }
1233    owl_list_append_element(in, owl_strdup(buff));
1234  }
1235  fclose(f);
1236  owl_free(ourfile);
1237  return(0);
1238#else
1239  return(-1);
1240#endif
1241}
1242
1243#ifdef HAVE_LIBZEPHYR
1244void owl_zephyr_process_events(owl_dispatch *d) {
1245  int zpendcount=0;
1246  ZNotice_t notice;
1247  struct sockaddr_in from;
1248  owl_message *m=NULL;
1249
1250  while(owl_zephyr_zpending() && zpendcount < 20) {
1251    if (owl_zephyr_zpending()) {
1252      ZReceiveNotice(&notice, &from);
1253      zpendcount++;
1254
1255      /* is this an ack from a zephyr we sent? */
1256      if (owl_zephyr_notice_is_ack(&notice)) {
1257        owl_zephyr_handle_ack(&notice);
1258        continue;
1259      }
1260
1261      /* if it's a ping and we're not viewing pings then skip it */
1262      if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
1263        continue;
1264      }
1265
1266      /* create the new message */
1267      m=owl_malloc(sizeof(owl_message));
1268      owl_message_create_from_znotice(m, &notice);
1269
1270      owl_global_messagequeue_addmsg(&g, m);
1271    }
1272  }
1273}
1274
1275#else
1276void owl_zephyr_process_events(owl_dispatch *d) {
1277 
1278}
1279#endif
Note: See TracBrowser for help on using the repository browser.