Changeset 8861654


Ignore:
Timestamp:
Jun 26, 2019, 11:12:14 PM (5 years ago)
Author:
GitHub <noreply@github.com>
Parents:
9a0d25d (diff), 0147aef (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Karl Ramm <xyzzy-github@1ts.org> (06/26/19 23:12:14)
git-committer:
GitHub <noreply@github.com> (06/26/19 23:12:14)
Message:
Merge 0147aef663eaf89b38b9abfc3d179593ee5e50fd into 9a0d25d1513e92f2b0c99d89ab5fc5ae2c061151
Files:
8 added
44 deleted
40 edited

Legend:

Unmodified
Added
Removed
  • AUTHORS

    r80c0fc7 r9e219d3  
    3232  Betsy Riley
    3333  Robert Jacobs
     34  Google Inc.
    3435
    3536BarnOwl is based on code from Owl, which was originally primarily
  • Makefile.am

    r4fd3c04 r8861654  
    6060CODELIST_SRCS=message.c mainwin.c popwin.c zephyr.c messagelist.c \
    6161     commands.c global.c text.c fmtext.c editwin.c \
    62      util.c logging.c \
     62     util.c logging.c ztext.c \
    6363     perlconfig.c keys.c functions.c zwrite.c viewwin.c help.c filter.c \
    6464     regex.c history.c view.c dict.c variable.c filterelement.c pair.c \
     
    6868     mainpanel.c msgwin.c sepbar.c editcontext.c signal.c closures.c
    6969
    70 NORMAL_SRCS = filterproc.c filterproc.h window.c window.h windowcb.c
     70NORMAL_SRCS = filterproc.c filterproc.h window.c window.h windowcb.c ztext.h
    7171
    7272BASE_SRCS = $(CODELIST_SRCS) $(NORMAL_SRCS)
  • fmtext.c

    rf271129 r4b2eef6  
    549549}
    550550
     551/* flattens a ztext parse tree into fmtext */
     552static void owl_fmtext_append_ztext_tree(owl_fmtext *f, ztext_env *tree, char attr, short fg)
     553{
     554  char *s;
     555  int i;
     556  bool handled = false;
     557  const struct {
     558    const char *tag;
     559    enum {SET,  MASK} mode;
     560    const char val;
     561  } TAGS[] = {
     562    {"", MASK, 0},
     563    {"@", MASK, 0},
     564    {"@bold", MASK, OWL_FMTEXT_ATTR_BOLD},
     565    {"@b", MASK, OWL_FMTEXT_ATTR_BOLD},
     566    {"@italic", MASK, OWL_FMTEXT_ATTR_UNDERLINE},
     567    {"@i", MASK, OWL_FMTEXT_ATTR_UNDERLINE},
     568    {"@roman", SET, OWL_FMTEXT_ATTR_NONE},
     569    {NULL, 0},
     570  };
     571
     572  if (tree->closer == '@' && tree->content == NULL) {
     573    owl_fmtext_append_attr(f, "@", attr, fg, OWL_COLOR_DEFAULT);
     574    return;
     575  }
     576
     577  for (i = 0; TAGS[i].tag != NULL; i++) {
     578    if (!strcasecmp(tree->label, TAGS[i].tag)) {
     579      if (TAGS[i].mode == MASK) {
     580        attr |= TAGS[i].val;
     581      } else if (TAGS[i].mode == SET) {
     582        attr = TAGS[i].val;
     583      }
     584      handled = true;
     585      break;
     586    }
     587  }
     588
     589  if (!handled) {
     590    /* continue the dubious practice of printing codes we don't understand */
     591    s = g_strdup_printf("%s%c", tree->label, tree->opener);
     592    owl_fmtext_append_attr(f, s, attr, fg, OWL_COLOR_DEFAULT);
     593    g_free(s);
     594  }
     595
     596  for (ztext_node *p = tree->content; p != NULL; p = p->next) {
     597    if (p->type == ZTEXT_NODE_STRING) {
     598      owl_fmtext_append_attr(f, p->string, attr, fg, OWL_COLOR_DEFAULT);
     599    } else if (p->type == ZTEXT_NODE_ENV) {
     600      if (!strcasecmp(p->env->label, "@color")) {
     601        s = ztext_strip(p->env);
     602        fg = owl_util_string_to_color(s);
     603        if (fg == OWL_COLOR_INVALID)
     604          fg = OWL_COLOR_DEFAULT;
     605        g_free(s);
     606      } else {
     607        owl_fmtext_append_ztext_tree(f, p->env, attr, fg);
     608      }
     609    }
     610  }
     611
     612  if (!handled) {
     613    s = g_strdup_printf("%c", tree->closer);
     614    owl_fmtext_append_attr(f, s, attr, fg, OWL_COLOR_DEFAULT);
     615    g_free(s);
     616  }
     617}
    551618
    552619/* Append the text 'text' to 'f' and interpret the zephyr style
     
    555622void owl_fmtext_append_ztext(owl_fmtext *f, const char *text)
    556623{
    557   int stacksize, curattrs, curcolor;
    558   const char *ptr, *txtptr, *tmpptr;
    559   char *buff;
    560   int attrstack[32], chrstack[32], colorstack[32];
    561 
    562   curattrs=OWL_FMTEXT_ATTR_NONE;
    563   curcolor=OWL_COLOR_DEFAULT;
    564   stacksize=0;
    565   txtptr=text;
    566   while (1) {
    567     ptr=strpbrk(txtptr, "@{[<()>]}");
    568     if (!ptr) {
    569       /* add all the rest of the text and exit */
    570       owl_fmtext_append_attr(f, txtptr, curattrs, curcolor, OWL_COLOR_DEFAULT);
    571       return;
    572     } else if (ptr[0]=='@') {
    573       /* add the text up to this point then deal with the stack */
    574       buff=g_new(char, ptr-txtptr+20);
    575       strncpy(buff, txtptr, ptr-txtptr);
    576       buff[ptr-txtptr]='\0';
    577       owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
    578       g_free(buff);
    579 
    580       /* update pointer to point at the @ */
    581       txtptr=ptr;
    582 
    583       /* now the stack */
    584 
    585       /* if we've hit our max stack depth, print the @ and move on */
    586       if (stacksize==32) {
    587         owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
    588         txtptr++;
    589         continue;
    590       }
    591 
    592       /* if it's an @@, print an @ and continue */
    593       if (txtptr[1]=='@') {
    594         owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
    595         txtptr+=2;
    596         continue;
    597       }
    598        
    599       /* if there's no opener, print the @ and continue */
    600       tmpptr=strpbrk(txtptr, "(<[{ ");
    601       if (!tmpptr || tmpptr[0]==' ') {
    602         owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
    603         txtptr++;
    604         continue;
    605       }
    606 
    607       /* check what command we've got, push it on the stack, start
    608          using it, and continue ... unless it's a color command */
    609       buff=g_new(char, tmpptr-ptr+20);
    610       strncpy(buff, ptr, tmpptr-ptr);
    611       buff[tmpptr-ptr]='\0';
    612       if (!strcasecmp(buff, "@bold")) {
    613         attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD;
    614         chrstack[stacksize]=tmpptr[0];
    615         colorstack[stacksize]=curcolor;
    616         stacksize++;
    617         curattrs|=OWL_FMTEXT_ATTR_BOLD;
    618         txtptr+=6;
    619         g_free(buff);
    620         continue;
    621       } else if (!strcasecmp(buff, "@b")) {
    622         attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD;
    623         chrstack[stacksize]=tmpptr[0];
    624         colorstack[stacksize]=curcolor;
    625         stacksize++;
    626         curattrs|=OWL_FMTEXT_ATTR_BOLD;
    627         txtptr+=3;
    628         g_free(buff);
    629         continue;
    630       } else if (!strcasecmp(buff, "@i")) {
    631         attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE;
    632         chrstack[stacksize]=tmpptr[0];
    633         colorstack[stacksize]=curcolor;
    634         stacksize++;
    635         curattrs|=OWL_FMTEXT_ATTR_UNDERLINE;
    636         txtptr+=3;
    637         g_free(buff);
    638         continue;
    639       } else if (!strcasecmp(buff, "@italic")) {
    640         attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE;
    641         chrstack[stacksize]=tmpptr[0];
    642         colorstack[stacksize]=curcolor;
    643         stacksize++;
    644         curattrs|=OWL_FMTEXT_ATTR_UNDERLINE;
    645         txtptr+=8;
    646         g_free(buff);
    647         continue;
    648       } else if (!strcasecmp(buff, "@")) {
    649         attrstack[stacksize]=OWL_FMTEXT_ATTR_NONE;
    650         chrstack[stacksize]=tmpptr[0];
    651         colorstack[stacksize]=curcolor;
    652         stacksize++;
    653         txtptr+=2;
    654         g_free(buff);
    655         continue;
    656 
    657         /* if it's a color read the color, set the current color and
    658            continue */
    659       } else if (!strcasecmp(buff, "@color")
    660                  && owl_global_is_colorztext(&g)) {
    661         g_free(buff);
    662         txtptr+=7;
    663         tmpptr=strpbrk(txtptr, "@{[<()>]}");
    664         if (tmpptr &&
    665             ((txtptr[-1]=='(' && tmpptr[0]==')') ||
    666              (txtptr[-1]=='<' && tmpptr[0]=='>') ||
    667              (txtptr[-1]=='[' && tmpptr[0]==']') ||
    668              (txtptr[-1]=='{' && tmpptr[0]=='}'))) {
    669 
    670           /* grab the color name */
    671           buff=g_new(char, tmpptr-txtptr+20);
    672           strncpy(buff, txtptr, tmpptr-txtptr);
    673           buff[tmpptr-txtptr]='\0';
    674 
    675           /* set it as the current color */
    676           curcolor=owl_util_string_to_color(buff);
    677           if (curcolor == OWL_COLOR_INVALID)
    678               curcolor = OWL_COLOR_DEFAULT;
    679           g_free(buff);
    680           txtptr=tmpptr+1;
    681           continue;
    682 
    683         } else {
    684 
    685         }
    686 
    687       } else {
    688         /* if we didn't understand it, we'll print it.  This is different from zwgc
    689          * but zwgc seems to be smarter about some screw cases than I am
    690          */
    691         g_free(buff);
    692         owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
    693         txtptr++;
    694         continue;
    695       }
    696 
    697     } else if (ptr[0]=='}' || ptr[0]==']' || ptr[0]==')' || ptr[0]=='>') {
    698       /* add the text up to this point first */
    699       buff=g_new(char, ptr-txtptr+20);
    700       strncpy(buff, txtptr, ptr-txtptr);
    701       buff[ptr-txtptr]='\0';
    702       owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
    703       g_free(buff);
    704 
    705       /* now deal with the closer */
    706       txtptr=ptr;
    707 
    708       /* first, if the stack is empty we must bail (just print and go) */
    709       if (stacksize==0) {
    710         buff=g_new(char, 5);
    711         buff[0]=ptr[0];
    712         buff[1]='\0';
    713         owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
    714         g_free(buff);
    715         txtptr++;
    716         continue;
    717       }
    718 
    719       /* if the closing char is what's on the stack, turn off the
    720          attribue and pop the stack */
    721       if ((ptr[0]==')' && chrstack[stacksize-1]=='(') ||
    722           (ptr[0]=='>' && chrstack[stacksize-1]=='<') ||
    723           (ptr[0]==']' && chrstack[stacksize-1]=='[') ||
    724           (ptr[0]=='}' && chrstack[stacksize-1]=='{')) {
    725         int i;
    726         stacksize--;
    727         curattrs=OWL_FMTEXT_ATTR_NONE;
    728         curcolor = colorstack[stacksize];
    729         for (i=0; i<stacksize; i++) {
    730           curattrs|=attrstack[i];
    731         }
    732         txtptr+=1;
    733         continue;
    734       } else {
    735         /* otherwise print and continue */
    736         buff=g_new(char, 5);
    737         buff[0]=ptr[0];
    738         buff[1]='\0';
    739         owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
    740         g_free(buff);
    741         txtptr++;
    742         continue;
    743       }
    744     } else {
    745       /* we've found an unattached opener, print everything and move on */
    746       buff=g_new(char, ptr-txtptr+20);
    747       strncpy(buff, txtptr, ptr-txtptr+1);
    748       buff[ptr-txtptr+1]='\0';
    749       owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
    750       g_free(buff);
    751       txtptr=ptr+1;
    752       continue;
    753     }
    754   }
    755 }
     624  ztext_env *tree = ztext_tree(text);
     625
     626  owl_fmtext_append_ztext_tree(f, tree,
     627                               OWL_FMTEXT_ATTR_NONE, OWL_COLOR_DEFAULT);
     628
     629  ztext_env_free(tree);
     630}
     631
    756632
    757633/* requires that the list values are strings or NULL.
  • owl.h

    r4fd3c04 r8861654  
    6262
    6363#include "window.h"
     64#include "ztext.h"
    6465
    6566extern const char *version;
  • perl/lib/BarnOwl.pm

    reea7bed4 r8861654  
    110110=head2 ztext_stylestrip STRING
    111111
    112 Strips zephyr formatting from a string and returns the result
     112Strips zephyr formatting barnowl understands from a string and returns the result
     113
     114=head2 ztext_stylestrip_full STRING
     115
     116Strips all the zephyr formatting from a string an returns the reuslt
     117
     118=head2 ztext_protect STRING
     119
     120Massage zephyr formatting to make it not interfere with more zephyr formatting.
    113121
    114122=head2 zephyr_getsubs
  • perl/lib/BarnOwl/Style.pm

    rfd8dfe7 ra13ad6f  
    1414{
    1515    local $_ = shift;
    16     if ( !(/\)/) ) {
    17         return '@b(' . $_ . ')';
    18     } elsif ( !(/\>/) ) {
    19         return '@b<' . $_ . '>';
    20     } elsif ( !(/\}/) ) {
    21         return '@b{' . $_ . '}';
    22     } elsif ( !(/\]/) ) {
    23         return '@b[' . $_ . ']';
    24     } else {
    25         my $txt = "\@b($_";
    26         $txt =~ s/\)/\)\@b\[\)\]\@b\(/g;
    27         return $txt . ')';
    28     }
     16    return '@b{' . BarnOwl::ztext_protect($_) . '}'
    2917}
    3018
  • perlglue.xs

    rd2ba33c r8861654  
    110110
    111111const utf8 *
     112ztext_protect(ztext)
     113        const char *ztext
     114        PREINIT:
     115                char *rv = NULL;
     116        CODE:
     117                rv = ztext_protect(ztext);
     118                RETVAL = rv;
     119        OUTPUT:
     120                RETVAL
     121        CLEANUP:
     122                g_free(rv);
     123
     124const utf8 *
     125ztext_stylestrip_full(ztext)
     126        const char *ztext
     127        PREINIT:
     128                char *rv = NULL;
     129        CODE:
     130                ztext_env *tree = ztext_tree(ztext);
     131                rv = ztext_strip(tree);
     132                ztext_env_free(tree);
     133                RETVAL = rv;
     134        OUTPUT:
     135                RETVAL
     136        CLEANUP:
     137                g_free(rv);
     138
     139const utf8 *
    112140zephyr_smartstrip_user(in)
    113141        const char *in
  • tester.c

    ra882637 r8861654  
    2626int call_filter_regtest(void);
    2727int owl_smartstrip_regtest(void);
     28int ztext_test(void);
    2829
    2930extern void owl_perl_xs_init(pTHX);
     
    116117  numfailures += call_filter_regtest();
    117118  numfailures += owl_smartstrip_regtest();
     119  numfailures += ztext_test();
    118120  if (numfailures) {
    119121      fprintf(stderr, "# *** WARNING: %d failures total\n", numfailures);
     
    10531055  return numfailed;
    10541056}
     1057
     1058static char *ztext_str(ztext_env *tree)
     1059{
     1060    /* Unambiguous representation of the parse tree */
     1061    char *s, *t, *u;
     1062
     1063    if (tree->opener) {
     1064        s = g_strdup_printf("{'%s%c'", tree->label, tree->opener);
     1065    } else {
     1066        s = g_strdup("{-");
     1067    }
     1068
     1069    for (ztext_node *p = tree->content; p != NULL; p = p->next) {
     1070        t = s;
     1071        if (p->type== ZTEXT_NODE_STRING) {
     1072            s = g_strdup_printf("%s |%s|", s, p->string);
     1073        } else if (p->type == ZTEXT_NODE_ENV) {
     1074            u = ztext_str(p->env);
     1075            s = g_strconcat(s, " ", u, NULL);
     1076            g_free(u);
     1077        }
     1078        g_free(t);
     1079    }
     1080
     1081    t = s;
     1082    if (tree->closer) {
     1083        s = g_strdup_printf("%s '%c'}", s, tree->closer);
     1084    } else {
     1085        s = g_strconcat(s, "}", NULL);
     1086    }
     1087    g_free(t);
     1088
     1089    return s;
     1090}
     1091
     1092char *ztext_ztext(ztext_env *tree)
     1093{
     1094    char *s, *t, *u;
     1095
     1096    if (tree->closer == '@' && tree->content == NULL)
     1097        return g_strdup("@@");
     1098
     1099    if (tree->opener) {
     1100        s = g_strdup_printf("%s%c", tree->label, tree->opener);
     1101    } else {
     1102        s = g_strdup("");
     1103    }
     1104
     1105    for (ztext_node *p = tree->content; p != NULL; p = p->next) {
     1106        t = s;
     1107        if (p->type == ZTEXT_NODE_STRING) {
     1108            s = g_strconcat(s, p->string, NULL);
     1109        } else if (p->type == ZTEXT_NODE_ENV) {
     1110            u = ztext_ztext(p->env);
     1111            s = g_strconcat(s, u, NULL);
     1112            g_free(u);
     1113        }
     1114        g_free(t);
     1115    }
     1116
     1117    if (tree->closer) {
     1118        t = s;
     1119        s = g_strdup_printf("%s%c", s, tree->closer);
     1120        g_free(t);
     1121    }
     1122
     1123    return s;
     1124}
     1125
     1126int ztext_test(void)
     1127{
     1128    int numfailed = 0;
     1129    char *s;
     1130    ztext_env *t;
     1131    char *d;
     1132
     1133#define CHECK_ZTEXT_STR(in, expected)                                         \
     1134    do {                                                                      \
     1135      t = ztext_tree(in);                                                     \
     1136      s = ztext_str(t);                                                       \
     1137      d = g_strdup_printf("ztext decode \"%s\" expected \"%s\" got \"%s\"",   \
     1138                          in, expected, s);                                   \
     1139      FAIL_UNLESS(d, !strcmp(s, expected));                                   \
     1140      ztext_env_free(t);                                                      \
     1141      g_free(d);                                                              \
     1142      g_free(s);                                                              \
     1143    } while (0)
     1144
     1145    CHECK_ZTEXT_STR("", "{-}");
     1146    CHECK_ZTEXT_STR("foo", "{- |foo|}");
     1147    CHECK_ZTEXT_STR("@{foo}", "{- {'@{' |foo| '}'}}");
     1148    CHECK_ZTEXT_STR("@bar{foo}", "{- {'@bar{' |foo| '}'}}");
     1149    CHECK_ZTEXT_STR("@bar{foo@bar}", "{- {'@bar{' |foo@bar| '}'}}");
     1150    CHECK_ZTEXT_STR("@bar{foo@@bar}", "{- {'@bar{' |foo| {'@@' '@'} |bar| '}'}}");
     1151    CHECK_ZTEXT_STR("@{foo@}bar}baz", "{- {'@{' |foo@| '}'} |bar}baz|}");
     1152    CHECK_ZTEXT_STR("foo@bar{baz@(bang})}",
     1153                    "{- |foo| {'@bar{' |baz| {'@(' |bang}| ')'} '}'}}");
     1154    CHECK_ZTEXT_STR("foo@bar{baz}", "{- |foo| {'@bar{' |baz| '}'}}");
     1155    CHECK_ZTEXT_STR("@bloop", "{- |@bloop|}");
     1156    CHECK_ZTEXT_STR("@{)}@{>}", "{- {'@{' |)| '}'} {'@{' |>| '}'}}");
     1157
     1158#define CHECK_ZTEXT_STRIP(in, expected)                                      \
     1159    do {                                                                     \
     1160      t = ztext_tree(in);                                                    \
     1161      s = ztext_strip(t);                                                    \
     1162      d = g_strdup_printf("ztext strip \"%s\" expected \"%s\" got \"%s\"",   \
     1163                          in, expected, s);                                  \
     1164      FAIL_UNLESS(d, !strcmp(s, expected));                                  \
     1165      ztext_env_free(t);                                                     \
     1166      g_free(d);                                                             \
     1167      g_free(s);                                                             \
     1168    } while (0)
     1169
     1170    CHECK_ZTEXT_STRIP("", "");
     1171    CHECK_ZTEXT_STRIP("foo", "foo");
     1172    CHECK_ZTEXT_STRIP("@{foo}", "foo");
     1173    CHECK_ZTEXT_STRIP("@bar{foo}", "foo");
     1174    CHECK_ZTEXT_STRIP("@bar{foo@bar}", "foo@bar");
     1175    CHECK_ZTEXT_STRIP("@bar{foo@@bar}", "foo@bar");
     1176    CHECK_ZTEXT_STRIP("@{foo@}bar}baz", "foo@bar}baz");
     1177    CHECK_ZTEXT_STRIP("foo@bar{baz@(bang})}", "foobazbang}");
     1178    CHECK_ZTEXT_STRIP("foo@bar{baz}", "foobaz");
     1179    CHECK_ZTEXT_STRIP("@bloop", "@bloop");
     1180    CHECK_ZTEXT_STRIP("@{)}@{>}", ")>");
     1181    CHECK_ZTEXT_STRIP("@color(blue)@font(fixed)marzipan", "marzipan");
     1182
     1183#define CHECK_ZTEXT_RT(in)                                                \
     1184    do {                                                                  \
     1185      t = ztext_tree(in);                                                 \
     1186      s = ztext_ztext(t);                                                 \
     1187      d = g_strdup_printf("ztext round-trip \"%s\" got \"%s\"", in, s);   \
     1188      FAIL_UNLESS(d, !strcmp(s, in));                                     \
     1189      ztext_env_free(t);                                                  \
     1190      g_free(s);                                                          \
     1191    } while (0)
     1192
     1193    CHECK_ZTEXT_RT("");
     1194    CHECK_ZTEXT_RT("foo");
     1195    CHECK_ZTEXT_RT("@{foo}");
     1196    CHECK_ZTEXT_RT("@bar{foo}");
     1197    CHECK_ZTEXT_RT("@bar{foo@bar}");
     1198    CHECK_ZTEXT_RT("@bar{foo@@bar}");
     1199    CHECK_ZTEXT_RT("@{foo@}bar}baz");
     1200    CHECK_ZTEXT_RT("foo@bar{baz@(bang})}");
     1201    CHECK_ZTEXT_RT("foo@bar{baz}");
     1202    CHECK_ZTEXT_RT("@bloop");
     1203    CHECK_ZTEXT_RT("@{)}@{>}");
     1204
     1205    /* fuzzzzzz */
     1206    srand48(getpid() + time(0));
     1207
     1208    char tango[32];
     1209    const char CHARS[] = "@abc ({<[]>})";
     1210
     1211    for(int i=0; i < 1000; i++) {
     1212        memset(tango, 0, sizeof(tango));
     1213        int l = lrand48() % sizeof(tango);
     1214        for (int j=0; j < l; j++) {
     1215            tango[j] = CHARS[lrand48() % (sizeof(CHARS) -1)];
     1216        }
     1217        CHECK_ZTEXT_RT(tango);
     1218    }
     1219
     1220#define CHECK_ZTEXT_PROTECT(in, expected)                                     \
     1221    do {                                                                      \
     1222      s = ztext_protect(in);                                                  \
     1223      d = g_strdup_printf("ztext protect \"%s\" expected \"%s\" got \"%s\"",  \
     1224                          in, expected, s);                                   \
     1225      FAIL_UNLESS(d, !strcmp(s, expected));                                   \
     1226      g_free(d);                                                              \
     1227      g_free(s);                                                              \
     1228    } while (0)
     1229
     1230    CHECK_ZTEXT_PROTECT("", "");
     1231    CHECK_ZTEXT_PROTECT("foo", "foo");
     1232    CHECK_ZTEXT_PROTECT("fo}o", "fo@(})o");
     1233    CHECK_ZTEXT_PROTECT("@[foo", "@[foo]");
     1234    CHECK_ZTEXT_PROTECT("})>]", "@(})@<)>@[>]@{]}");
     1235
     1236    return numfailed;
     1237}
  • ChangeLog

    r6f87658 r678a7650  
     11.10
     2 * No changes above what's already in 1.10rc1
     3
     41.10rc1
     5 * Numerous autotools/build machinery fixes -andersk@mit.edu
     6 * Numerous code correctness and simplification/cleanup fixes -andersk@mit.edu
     7 * Add and use a cpanfile documenting perl module dependencies -jgross@mit.edu
     8 * Add Travis configuration -jgross@mit.edu
     9 * Avoid strchrnul -andersk@mit.edu
     10 * Numerous IRC fixes -jgross@mit.edu
     11 * Improve smartnarrow and smartfilter documentation -jgross@mit.edu
     12 * filterproc: Rewrite using GIOChannel -andersk@mit.edu
     13 * Implement :twitter-favorite -nelhage@nelhage.com
     14 * Kill the client-side tweet length check. -nelhage@nelhage.com
     15 * squelch the Twitter legacy_list_api warnings -nelhage@nelhage.com
     16 * Use SSL for Twitter by default -adehnert@mit.edu
     17 * Humanize zsigs -andersk@mit.edu
     18 * Show Zephyr charset in info popup -andersk@mit.edu
     19 * Fix Jabber SRV record support (at one point fixed connecting via jabber to google talk or facebook) -james2vegas@aim.com
     20 * fix cmd_join in BarnOwl/Module/IRC.pm -james2vegas@aim.com
     21 * Add a ~/.owl/ircchannels file, persist channels -jgross@mit.edu
     22 * Added hooks for user going idle or active. -jgross@mit.edu
     23 * Support channel-or-user IRC commands, and setup irc-msg to use it. -ezyang@mit.edu
     24 * Refactor perl calls through a single method -jgross@mit.edu
     25 * Really support building Perl modules from a separate builddir -andersk@mit.edu
     26 * Get rid of all our embedded copies of Module::Install -andersk@mit.edu
     27 * Don't let new_variable_* overriding previously set values -rnjacobs@mit.edu
     28 * Messages sent to 'class messages' are not personal -jgross@mit.edu
     29 * Expose message_matches_filter to perl -jgross@mit.edu
     30 * Fail fast on -c filsrv, which most people won't have permission to send to -rnjacobs@mit.edu
     31 * zcrypt: Use getopt_long for argument parsing -andersk@mit.edu
     32 * zcrypt: Accept -help and --version -andersk@mit.edu
     33 * barnowl --help: Write to stdout and exit successfully -andersk@mit.edu
     34 * Don't swallow errors in :unsuball -davidben@mit.edu
     35 * Allow testing in a separate build directory -andersk@mit.edu
     36 * Add support for arbitrary Perl subs for getters and setters for barnowl variables -glasgall@mit.edu
     37 * owl_zephyr_loadsubs: Don’t leak memory on error opening ~/.zephyr.subs -andersk@mit.edu
     38 * Make :loadsubs reload instanced personals too -davidben@mit.edu
     39 * Fix some undefined behavior in filter.c, caught by clang scan-build -jgross@mit.edu
     40 * Die on a failed zephyr_zwrite; don't silently ignore it -jgross@mit.edu
     41 * Fix a memory leak in zcrypt.c, caught by clang scan-build -jgross@mit.edu
     42 * zcrypt: Make gpg stop messing around in ~/.gnupg -andersk@mit.edu
     43 * Fix display of pseudologins -davidben@mit.edu
     44 * Unbundle random Facebook module libraries -davidben@mit.edu
     45 * Replace deprecated GLib < 2.31.0 APIs -andersk@mit.edu
     46 * Abstract g->interrupt_lock -andersk@mit.edu
     47 * zephyr: Replace outgoing default format with a small URL -geofft@mit.edu
     48
    1491.9
    250 * Update Jabber module for Net::DNS changes -james2vegas@aim.com
  • codelist.pl

    r06adc25 r4fd3c04  
    1818            && !/^XS/
    1919            && !/\/\*/
    20             && !/ZWRITEOPTIONS/
    21             && !/owlfaim_priv/)
     20            && !/ZWRITEOPTIONS/)
    2221        {
    2322
  • commands.c

    r8fcd3e7 r4fd3c04  
    122122              "      Send to the specified opcode\n"),
    123123
    124   OWLCMD_ARGS("aimwrite", owl_command_aimwrite, OWL_CTX_INTERACTIVE,
    125               "send an AIM message",
    126               "aimwrite <user> [-m <message...>]",
    127               "Send an aim message to a user.\n\n"
    128               "The following options are available:\n\n"
    129               "-m    Specifies a message to send without prompting.\n"),
    130 
    131124  OWLCMD_ARGS("loopwrite", owl_command_loopwrite, OWL_CTX_INTERACTIVE,
    132125              "send a loopback message",
     
    153146  OWLCMD_ARGS("set", owl_command_set, OWL_CTX_ANY,
    154147              "set a variable value",
    155               "set [-q] [<variable>] [<value>]\n"
     148              "set [-q] <variable> [<value>]\n"
    156149              "set",
    157150              "Set the named variable to the specified value.  If no\n"
     
    234227              "Execute the BarnOwl commands in <filename>.\n"),
    235228
    236   OWLCMD_ARGS("aim", owl_command_aim, OWL_CTX_INTERACTIVE,
    237               "AIM specific commands",
    238               "aim search <email>",
    239               ""),
    240 
    241229  OWLCMD_ARGS("addbuddy", owl_command_addbuddy, OWL_CTX_INTERACTIVE,
    242230              "add a buddy to a buddylist",
    243231              "addbuddy <protocol> <screenname>",
    244               "Add the named buddy to your buddylist.  <protocol> can be aim or zephyr\n"),
     232              "Add the named buddy to your buddylist.  <protocol> must be zephyr\n"),
    245233
    246234  OWLCMD_ARGS("delbuddy", owl_command_delbuddy, OWL_CTX_INTERACTIVE,
    247235              "delete a buddy from a buddylist",
    248236              "delbuddy <protocol> <screenname>",
    249               "Delete the named buddy from your buddylist.  <protocol> can be aim or zephyr\n"),
    250 
    251   OWLCMD_ARGS("join", owl_command_join, OWL_CTX_INTERACTIVE,
    252               "join a chat group",
    253               "join aim <groupname> [exchange]",
    254               "Join the AIM chatroom with 'groupname'.\n"),
     237              "Delete the named buddy from your buddylist.  <protocol> must be zephyr\n"),
    255238
    256239  OWLCMD_ARGS("smartzpunt", owl_command_smartzpunt, OWL_CTX_INTERACTIVE,
     
    308291              "znol [-f file]",
    309292              "Print a znol-style listing of users logged in"),
    310 
    311   OWLCMD_VOID("alist", owl_command_alist, OWL_CTX_INTERACTIVE,
    312               "List AIM users logged in",
    313               "alist",
    314               "Print a listing of AIM users logged in"),
    315293
    316294  OWLCMD_VOID("blist", owl_command_blist, OWL_CTX_INTERACTIVE,
     
    470448              "use the default.\n"),
    471449
    472   OWLCMD_ARGS("aaway", owl_command_aaway, OWL_CTX_INTERACTIVE,
    473               "Set, enable or disable AIM away message",
    474               "aaway [ on | off | toggle ]\n"
    475               "aaway <message>",
    476               "Turn on or off the AIM away message.  If 'message' is\n"
    477               "specified turn on aaway with that message, otherwise\n"
    478               "use the default.\n"),
    479 
    480450  OWLCMD_ARGS("away", owl_command_away, OWL_CTX_INTERACTIVE,
    481451              "Set, enable or disable all away messages",
     
    486456              "otherwise use the default.\n"
    487457              "\n"
    488               "SEE ALSO: aaway, zaway"),
     458              "SEE ALSO: zaway"),
     459
     460  OWLCMD_ARGS("flush-logs", owl_command_flushlogs, OWL_CTX_ANY,
     461              "flush the queue of messages waiting to be logged",
     462              "flush-logs [-f | --force] [-q | --quiet]",
     463              "If BarnOwl failed to log a file, this command tells\n"
     464              "BarnOwl to try logging the messages that have since\n"
     465              "come in, and to resume logging normally.\n"
     466              "\n"
     467              "Normally, if logging any of these messages fails,\n"
     468              "that message is added to the queue of messages waiting\n"
     469              "to be logged, and any new messages are deferred until\n"
     470              "the next :flush-logs.  If the --force flag is passed,\n"
     471              "any messages on the queue which cannot successfully be\n"
     472              "logged are dropped, and BarnOwl will resume logging\n"
     473              "normally.\n"
     474              "\n"
     475              "Unless --quiet is passed, a message is printed about\n"
     476              "how many logs there are to flush."),
    489477
    490478  OWLCMD_ARGS("load-subs", owl_command_loadsubs, OWL_CTX_ANY,
     
    530518              "    body       -  message body\n"
    531519              "    hostname   -  hostname of sending host\n"
    532               "    type       -  message type (zephyr, aim, admin)\n"
     520              "    type       -  message type (zephyr, admin)\n"
    533521              "    direction  -  either 'in' 'out' or 'none'\n"
    534522              "    login      -  either 'login' 'logout' or 'none'\n"
     
    754742          "no argument, it makes search highlighting inactive."),
    755743
    756   OWLCMD_ARGS("aimlogin", owl_command_aimlogin, OWL_CTX_ANY,
    757               "login to an AIM account",
    758               "aimlogin <screenname> [<password>]\n",
    759               ""),
    760 
    761   OWLCMD_ARGS("aimlogout", owl_command_aimlogout, OWL_CTX_ANY,
    762               "logout from AIM",
    763               "aimlogout\n",
    764               ""),
    765 
    766744  OWLCMD_ARGS("error", owl_command_error, OWL_CTX_ANY,
    767745              "Display an error message",
     
    10901068    }
    10911069  }
    1092   owl_function_buddylist(0, 1, file);
     1070  owl_function_buddylist(1, file);
    10931071  return(NULL);
    10941072}
    10951073
    1096 void owl_command_alist(void)
    1097 {
    1098   owl_function_buddylist(1, 0, NULL);
    1099 }
    1100 
    11011074void owl_command_blist(void)
    11021075{
    1103   owl_function_buddylist(1, 1, NULL);
     1076  owl_function_buddylist(1, NULL);
    11041077}
    11051078
     
    11171090{
    11181091  owl_function_makemsg("BarnOwl version %s", version);
    1119 }
    1120 
    1121 char *owl_command_aim(int argc, const char *const *argv, const char *buff)
    1122 {
    1123   if (argc<2) {
    1124     owl_function_makemsg("not enough arguments to aim command");
    1125     return(NULL);
    1126   }
    1127 
    1128   if (!strcmp(argv[1], "search")) {
    1129     if (argc!=3) {
    1130       owl_function_makemsg("not enough arguments to aim search command");
    1131       return(NULL);
    1132     }
    1133     owl_aim_search(argv[2]);
    1134   } else {
    1135     owl_function_makemsg("unknown subcommand '%s' for aim command", argv[1]);
    1136     return(NULL);
    1137   }
    1138   return(NULL);
    11391092}
    11401093
     
    11461099  }
    11471100
    1148   if (!strcasecmp(argv[1], "aim")) {
    1149     if (!owl_global_is_aimloggedin(&g)) {
    1150       owl_function_makemsg("addbuddy: You must be logged into aim to use this command.");
    1151       return(NULL);
    1152     }
    1153     /*
    1154     owl_function_makemsg("This function is not yet operational.  Stay tuned.");
    1155     return(NULL);
    1156     */
    1157     owl_aim_addbuddy(argv[2]);
    1158     owl_function_makemsg("%s added as AIM buddy for %s", argv[2], owl_global_get_aim_screenname(&g));
    1159   } else if (!strcasecmp(argv[1], "zephyr")) {
     1101  if (!strcasecmp(argv[1], "zephyr")) {
    11601102    owl_zephyr_addbuddy(argv[2]);
    11611103    owl_function_makemsg("%s added as zephyr buddy", argv[2]);
    11621104  } else {
    1163     owl_function_makemsg("addbuddy: currently the only supported protocols are 'zephyr' and 'aim'");
     1105    owl_function_makemsg("addbuddy: currently the only supported protocol is 'zephyr'");
    11641106  }
    11651107
     
    11741116  }
    11751117
    1176   if (!strcasecmp(argv[1], "aim")) {
    1177     if (!owl_global_is_aimloggedin(&g)) {
    1178       owl_function_makemsg("delbuddy: You must be logged into aim to use this command.");
    1179       return(NULL);
    1180     }
    1181     owl_aim_delbuddy(argv[2]);
    1182     owl_function_makemsg("%s deleted as AIM buddy for %s", argv[2], owl_global_get_aim_screenname(&g));
    1183   } else if (!strcasecmp(argv[1], "zephyr")) {
     1118  if (!strcasecmp(argv[1], "zephyr")) {
    11841119    owl_zephyr_delbuddy(argv[2]);
    11851120    owl_function_makemsg("%s deleted as zephyr buddy", argv[2]);
    11861121  } else {
    1187     owl_function_makemsg("delbuddy: currently the only supported protocols are 'zephyr' and 'aim'");
    1188   }
    1189 
    1190   return(NULL);
    1191 }
    1192 
    1193 char *owl_command_join(int argc, const char *const *argv, const char *buff)
    1194 {
    1195   if (argc!=3 && argc!=4) {
    1196     owl_function_makemsg("usage: join <protocol> <buddyname> [exchange]");
    1197     return(NULL);
    1198   }
    1199 
    1200   if (!strcasecmp(argv[1], "aim")) {
    1201     if (!owl_global_is_aimloggedin(&g)) {
    1202       owl_function_makemsg("join aim: You must be logged into aim to use this command.");
    1203       return(NULL);
    1204     }
    1205     if (argc==3) {
    1206       owl_aim_chat_join(argv[2], 4);
    1207     } else {
    1208       owl_aim_chat_join(argv[2], atoi(argv[3]));
    1209     }
    1210     /* owl_function_makemsg("%s deleted as AIM buddy for %s", argv[2], owl_global_get_aim_screenname(&g)); */
    1211   } else {
    1212     owl_function_makemsg("join: currently the only supported protocol is 'aim'");
    1213   }
     1122    owl_function_makemsg("delbuddy: currently the only supported protocol is 'zephyr'");
     1123  }
     1124
    12141125  return(NULL);
    12151126}
     
    14371348}
    14381349
     1350char *owl_command_flushlogs(int argc, const char *const *argv, const char *buff)
     1351{
     1352  bool force = false;
     1353  bool quiet = false;
     1354  int i;
     1355
     1356  for (i = 1; i < argc; i++) {
     1357    if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--force")) {
     1358      force = true;
     1359    } else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--quiet")) {
     1360      quiet = true;
     1361    } else {
     1362      owl_function_makemsg("Invalid flag to flush-logs: %s", argv[i]);
     1363    }
     1364  }
     1365  owl_log_flush_logs(force, quiet);
     1366  return NULL;
     1367}
     1368
    14391369char *owl_command_loadsubs(int argc, const char *const *argv, const char *buff)
    14401370{
     
    15021432
    15031433
    1504 char *owl_command_aaway(int argc, const char *const *argv, const char *buff)
    1505 {
    1506   if ((argc==1) ||
    1507       ((argc==2) && !strcmp(argv[1], "on"))) {
    1508     owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
    1509     owl_function_aaway_on();
    1510     return NULL;
    1511   }
    1512 
    1513   if (argc==2 && !strcmp(argv[1], "off")) {
    1514     owl_function_aaway_off();
    1515     return NULL;
    1516   }
    1517 
    1518   if (argc==2 && !strcmp(argv[1], "toggle")) {
    1519     owl_function_aaway_toggle();
    1520     return NULL;
    1521   }
    1522 
    1523   buff = skiptokens(buff, 1);
    1524   owl_global_set_aaway_msg(&g, buff);
    1525   owl_function_aaway_on();
    1526   return NULL;
    1527 }
    1528 
    1529 
    15301434char *owl_command_away(int argc, const char *const *argv, const char *buff)
    15311435{
     
    15361440      (argc == 2 && !strcmp(argv[1], "on"))) {
    15371441    away_off = false;
    1538     owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
    15391442    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
    15401443  } else if (argc == 2 && !strcmp(argv[1], "off")) {
     
    15481451
    15491452  if (away_off) {
    1550     owl_function_aaway_off();
    15511453    owl_function_zaway_off();
    15521454    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_off", 0, NULL);
    15531455    owl_function_makemsg("Away messages off.");
    15541456  } else if (message != NULL) {
    1555     owl_global_set_aaway_msg(&g, message);
    15561457    owl_global_set_zaway_msg(&g, message);
    1557     owl_function_aaway_on();
    15581458    owl_function_zaway_on();
    15591459    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 1, &message);
    15601460    owl_function_makemsg("Away messages set (%s).", message);
    15611461  } else {
    1562     owl_function_aaway_on();
    15631462    owl_function_zaway_on();
    15641463    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 0, NULL);
     
    20011900  }
    20021901  return(NULL);
    2003 }
    2004 
    2005 char *owl_command_aimwrite(int argc, const char *const *argv, const char *buff)
    2006 {
    2007   char *message = NULL;
    2008   GString *recip = g_string_new("");
    2009   const char *const *myargv;
    2010   int myargc;
    2011  
    2012   if (!owl_global_is_aimloggedin(&g)) {
    2013     owl_function_error("You are not logged in to AIM.");
    2014     goto err;
    2015   }
    2016 
    2017   /* Skip argv[0]. */
    2018   myargv = argv+1;
    2019   myargc = argc-1;
    2020   while (myargc) {
    2021     if (!strcmp(myargv[0], "-m")) {
    2022       if (myargc <= 1) {
    2023         owl_function_error("No message specified.");
    2024         goto err;
    2025       }
    2026       /* Once we have -m, gobble up everything else on the line */
    2027       myargv++;
    2028       myargc--;
    2029       message = g_strjoinv(" ", (char**)myargv);
    2030       break;
    2031     } else {
    2032       /* squish arguments together to make one screenname w/o spaces for now */
    2033       g_string_append(recip, myargv[0]);
    2034       myargv++;
    2035       myargc--;
    2036     }
    2037   }
    2038 
    2039   if (recip->str[0] == '\0') {
    2040     owl_function_error("No recipient specified");
    2041     goto err;
    2042   }
    2043 
    2044   if (message != NULL)
    2045     owl_function_aimwrite(recip->str, message, false);
    2046   else
    2047     owl_function_aimwrite_setup(recip->str);
    2048  err:
    2049   g_string_free(recip, true);
    2050   g_free(message);
    2051   return NULL;
    20521902}
    20531903
     
    26172467}
    26182468
    2619 char *owl_command_aimlogin(int argc, const char *const *argv, const char *buff)
    2620 {
    2621   if ((argc<2) || (argc>3)) {
    2622     owl_function_makemsg("Wrong number of arguments to aimlogin command");
    2623     return(NULL);
    2624   }
    2625 
    2626   /* if we get two arguments, ask for the password */
    2627   if (argc==2) {
    2628     owl_editwin *e = owl_function_start_password("AIM Password: ");
    2629     owl_editwin_set_cbdata(e, g_strdup(argv[1]), g_free);
    2630     owl_editwin_set_callback(e, owl_callback_aimlogin);
    2631     return(NULL);
    2632   } else {
    2633     owl_function_aimlogin(argv[1], argv[2]);
    2634   }
    2635 
    2636   /* this is a test */
    2637   return(NULL);
    2638 }
    2639 
    2640 char *owl_command_aimlogout(int argc, const char *const *argv, const char *buff)
    2641 {
    2642   /* clear the buddylist */
    2643   owl_buddylist_clear(owl_global_get_buddylist(&g));
    2644 
    2645   owl_aim_logout();
    2646   return(NULL);
    2647 }
    2648 
    26492469CALLER_OWN char *owl_command_getstyle(int argc, const char *const *argv, const char *buff)
    26502470{
  • configure.ac

    r77dfeb1 r9a0d25d  
    11dnl Process this file with autoconf to produce a configure script.
    2 AC_INIT([BarnOwl],[1.10dev],[bug-barnowl@mit.edu])
     2AC_INIT([BarnOwl],[1.11dev],[bug-barnowl@mit.edu])
    33AM_INIT_AUTOMAKE([1.7.0 foreign std-options -Wall -Wno-portability])
    44AM_MAINTAINER_MODE([enable])
     
    5454  [with_zephyr=check])
    5555
    56 AC_ARG_WITH([krb4],
    57   AS_HELP_STRING([--with-krb4],
    58                  [Build with kerberos IV]))
    59 
    6056AS_IF([test "x$with_zephyr" != xno],
    61   [have_krb4=no
    62 
    63    AS_IF([test "x$with_krb4" != "xno"],
    64    [AC_MSG_CHECKING([for Kerberos IV])
    65     AS_IF([krb5-config krb4 --libs >/dev/null 2>&1],
    66       [AC_MSG_RESULT([yes])
    67        have_krb4=yes
    68        AC_DEFINE([HAVE_KERBEROS_IV], [1], [Define if you have kerberos IV])
    69        AM_CFLAGS="${AM_CFLAGS} `krb5-config krb4 --cflags`"
    70        LIBS="${LIBS} `krb5-config krb4 --libs`"
    71       ],
    72       [AC_MSG_RESULT([no])
    73        AS_IF([test "x$with_krb4" = "xyes"],
    74              [AC_MSG_ERROR([Kerberos IV requested but not found])])])])
    75 
    76    AS_IF([test "x$have_krb4" != xyes],
    77      [PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto],
    78         [AM_CFLAGS="${AM_CFLAGS} ${LIBCRYPTO_CFLAGS}"
    79          LIBS="${LIBS} ${LIBCRYPTO_LIBS}"
    80         ],
    81         [PKG_CHECK_MODULES([OPENSSL], [openssl],
    82            [AM_CFLAGS="${AM_CFLAGS} ${OPENSSL_CFLAGS}"
    83             LIBS="${LIBS} ${OPENSSL_LIBS}"
    84            ])])])
     57  [PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto],
     58     [AM_CFLAGS="${AM_CFLAGS} ${LIBCRYPTO_CFLAGS}"
     59      LIBS="${LIBS} ${LIBCRYPTO_LIBS}"
     60     ],
     61     [PKG_CHECK_MODULES([OPENSSL], [openssl],
     62        [AM_CFLAGS="${AM_CFLAGS} ${OPENSSL_CFLAGS}"
     63         LIBS="${LIBS} ${OPENSSL_LIBS}"
     64        ])])
    8565
    8666   AC_CHECK_LIB([zephyr], [ZGetSender],
     
    10282AC_CHECK_FUNCS([use_default_colors])
    10383AC_CHECK_FUNCS([resizeterm], [], [AC_MSG_ERROR([No resizeterm found])])
    104 AC_CHECK_FUNCS([des_string_to_key DES_string_to_key], [HAVE_DES_STRING_TO_KEY=1])
    105 AC_CHECK_FUNCS([des_ecb_encrypt DES_ecb_encrypt], [HAVE_DES_ECB_ENCRYPT=1])
    106 AC_CHECK_FUNCS([des_key_sched DES_key_sched], [HAVE_DES_KEY_SCHED=1])
     84AC_CHECK_FUNCS([DES_string_to_key], [HAVE_DES_STRING_TO_KEY=1])
     85AC_CHECK_FUNCS([DES_ecb_encrypt], [HAVE_DES_ECB_ENCRYPT=1])
     86AC_CHECK_FUNCS([DES_key_sched], [HAVE_DES_KEY_SCHED=1])
    10787
    10888dnl Checks for header files.
     
    176156AX_APPEND_COMPILE_FLAGS([-Wno-format-zero-length],[AM_CFLAGS])
    177157
    178 AX_APPEND_COMPILE_FLAGS([-Wno-pointer-sign -Wno-empty-body -Wno-unused-value],[LIBFAIM_CFLAGS])
    179 
    180158AM_CONDITIONAL([ENABLE_ZCRYPT], [test "$HAVE_DES_STRING_TO_KEY" && dnl
    181159                                 test "$HAVE_DES_KEY_SCHED" && dnl
     
    183161
    184162AM_CFLAGS="$AM_CFLAGS -D_XOPEN_SOURCE=600"
    185 dnl Define _BSD_SOURCE because zephyr needs caddr_t.
    186 AM_CFLAGS="$AM_CFLAGS -D_BSD_SOURCE"
     163dnl Define _BSD_SOURCE/_DEFAULT_SOURCE because zephyr needs caddr_t.
     164AM_CFLAGS="$AM_CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE"
    187165dnl Define __EXTENSIONS__ for strcasecmp on Solaris.
    188166AM_CFLAGS="$AM_CFLAGS -D__EXTENSIONS__"
     
    194172
    195173AC_SUBST([AM_CFLAGS])
    196 AC_SUBST([LIBFAIM_CFLAGS])
    197174
    198175AC_SUBST(XSUBPPDIR)
     
    213190AC_SUBST([abs_srcdir])
    214191
    215 AC_CONFIG_FILES([Makefile compat/Makefile libfaim/Makefile perl/Makefile perl/modules/Makefile])
     192AC_CONFIG_FILES([Makefile compat/Makefile perl/Makefile perl/modules/Makefile])
    216193AC_OUTPUT
  • doc/advanced.txt

    rc82b055 r4fd3c04  
    4242     realm         zephyr realm
    4343     body          message body
    44      type          message type ('zephyr', 'aim', 'admin')
     44     type          message type ('zephyr', 'admin')
    4545     direction     either 'in' 'out' or 'none'\n"
    4646     login         either 'login' 'logout' or 'none'\n"
     
    103103All owl::Message objects contain the following methods:
    104104
    105     type      - returns the type of the message ("zephyr", "aim", "admin")
     105    type      - returns the type of the message ("zephyr", "admin")
    106106    direction - returns "in" or "out" for incoming or outgoing messages
    107107    time      - returns a string of the time when the message showed up
     
    126126
    127127    header      - returns the admin message header line  (admin)
    128     is_personal - returns true if this is a personal message (aim,zephyr)
     128    is_personal - returns true if this is a personal message (zephyr)
    129129    is_private  - returns true if this was a private message (zephyr)
    130130    login_tty   - returns the login tty for login messages (zephyr)
  • doc/intro.txt

    rd7cc50b r4fd3c04  
    88
    99Owl is a tty, curses-based instant messaging client.  This is a quick
    10 guide to learning how to use it.  Currently Owl supports AIM & zephyr,
     10guide to learning how to use it.  Currently Owl supports zephyr,
    1111but other messaging protocols, including Jabber, are on the way.  Some
    1212major features of owl include:
     
    7373If you wish to send to a class/instance pair simply supply -c and -i
    7474arguments to the zwrite command as you normally would.
    75 
    76 Sending an AIM message
    77 ----------------------
    78 
    79 Before sending an AIM message you must login to AOL Instant Messenger.
    80 Use the 'aimlogin' command, with your screenname as an argument:
    81 
    82      aimlogin <screenname>
    83 
    84 You will be prompted for your password, which you must enter.  Once
    85 you are successfully logged in you can send an AIM message by pressing
    86 the 'a' key, which will bring up an 'aimwrite' command:
    87 
    88      aimwrite <screenname>
    89 
    90 Supply the screen name you wish to write to as an argument and then
    91 send the message just as you would send a zephyr, as described above.
    9275
    9376Manipulating Messages
     
    256239     auto             Messages generated by automated programs
    257240     out              Messages sent from you to another user
    258      aim              AIM messages
    259241     zephyr           Zephyr messages
    260242     trash            "Trash" messages
  • filter.c

    r7dcef03 r9e596f5  
    1616owl_filter *owl_filter_new(const char *name, int argc, const char *const *argv)
    1717{
     18  return owl_filter_new_colored(name, argc, argv, OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
     19}
     20
     21owl_filter *owl_filter_new_colored(const char *name, int argc, const char *const *argv, int fgcolor, int bgcolor)
     22{
    1823  owl_filter *f;
    1924
     
    2126
    2227  f->name=g_strdup(name);
    23   f->fgcolor=OWL_COLOR_DEFAULT;
    24   f->bgcolor=OWL_COLOR_DEFAULT;
    25 
    26   /* first take arguments that have to come first */
    27   /* set the color */
    28   while ( argc>=2 && ( !strcmp(argv[0], "-c") ||
    29                        !strcmp(argv[0], "-b") ) ) {
    30     if (owl_util_string_to_color(argv[1])==OWL_COLOR_INVALID) {
    31       owl_function_error("The color '%s' is not available, using default.", argv[1]);
    32     } else {
    33       switch (argv[0][1]) {
    34       case 'c':
    35         f->fgcolor=owl_util_string_to_color(argv[1]);
    36         break;
    37       case 'b':
    38         f->bgcolor=owl_util_string_to_color(argv[1]);
    39         break;
    40       }
    41     }
    42     argc-=2;
    43     argv+=2;
    44   }
     28  f->fgcolor = fgcolor;
     29  f->bgcolor = bgcolor;
    4530
    4631  if (!(f->root = owl_filter_parse_expression(argc, argv, NULL))) {
  • filterproc.c

    r7155955 re8db357  
    11#include "filterproc.h"
    22#include <sys/wait.h>
    3 #include <fcntl.h>
     3#include <string.h>
    44#include <glib.h>
    5 #include <poll.h>
    6 #include <string.h>
    7 #include <unistd.h>
    85
    9 /* Even in case of error, send_receive is responsible for closing wfd
    10  * (to EOF the child) and rfd (for consistency). */
    11 static int send_receive(int rfd, int wfd, const char *out, char **in)
     6struct filter_data {
     7  const char **in;
     8  const char *in_end;
     9  GString *out_str;
     10  GMainLoop *loop;
     11  int err;
     12};
     13
     14static gboolean filter_stdin(GIOChannel *channel, GIOCondition condition, gpointer data_)
    1215{
    13   GString *str = g_string_new("");
    14   char buf[1024];
    15   nfds_t nfds;
    16   int err = 0;
    17   struct pollfd fds[2];
     16  struct filter_data *data = data_;
     17  gboolean done = condition & (G_IO_ERR | G_IO_HUP);
    1818
    19   fcntl(rfd, F_SETFL, O_NONBLOCK | fcntl(rfd, F_GETFL));
    20   fcntl(wfd, F_SETFL, O_NONBLOCK | fcntl(wfd, F_GETFL));
    21 
    22   fds[0].fd = rfd;
    23   fds[0].events = POLLIN;
    24   fds[1].fd = wfd;
    25   fds[1].events = POLLOUT;
    26 
    27   if(!out || !*out) {
    28     /* Nothing to write. Close our end so the child doesn't hang waiting. */
    29     close(wfd); wfd = -1;
    30     out = NULL;
     19  if (condition & G_IO_OUT) {
     20    gsize n;
     21    GIOStatus ret = g_io_channel_write_chars(channel, *data->in, data->in_end - *data->in, &n, NULL);
     22    *data->in += n;
     23    if (ret == G_IO_STATUS_ERROR)
     24      data->err = 1;
     25    if (ret == G_IO_STATUS_ERROR || *data->in == data->in_end)
     26      done = TRUE;
    3127  }
    3228
    33   while(1) {
    34     if(out && *out) {
    35       nfds = 2;
    36     } else {
    37       nfds = 1;
    38     }
    39     err = poll(fds, nfds, -1);
    40     if(err < 0) {
    41       break;
    42     }
    43     if(out && *out) {
    44       if(fds[1].revents & POLLOUT) {
    45         err = write(wfd, out, strlen(out));
    46         if(err > 0) {
    47           out += err;
    48         }
    49         if(err < 0) {
    50           out = NULL;
    51         }
    52       }
    53       if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) {
    54         close(wfd); wfd = -1;
    55         out = NULL;
    56       }
    57     }
    58     if(fds[0].revents & POLLIN) {
    59       err = read(rfd, buf, sizeof(buf));
    60       if(err <= 0) {
    61         break;
    62       }
    63       g_string_append_len(str, buf, err);
    64     } else if(fds[0].revents & (POLLHUP | POLLERR)) {
    65       err = 0;
    66       break;
     29  if (condition & G_IO_ERR)
     30    data->err = 1;
     31
     32  if (done)
     33    g_io_channel_shutdown(channel, TRUE, NULL);
     34  return !done;
     35}
     36
     37static gboolean filter_stdout(GIOChannel *channel, GIOCondition condition, gpointer data_)
     38{
     39  struct filter_data *data = data_;
     40  gboolean done = condition & (G_IO_ERR | G_IO_HUP);
     41
     42  if (condition & (G_IO_IN | G_IO_HUP)) {
     43    gchar *buf;
     44    gsize n;
     45    GIOStatus ret = g_io_channel_read_to_end(channel, &buf, &n, NULL);
     46    g_string_append_len(data->out_str, buf, n);
     47    g_free(buf);
     48    if (ret == G_IO_STATUS_ERROR) {
     49      data->err = 1;
     50      done = TRUE;
    6751    }
    6852  }
    6953
    70   if (wfd >= 0) close(wfd);
    71   close(rfd);
    72   *in = g_string_free(str, err < 0);
    73   return err;
     54  if (condition & G_IO_ERR)
     55    data->err = 1;
     56
     57  if (done) {
     58    g_io_channel_shutdown(channel, TRUE, NULL);
     59    g_main_loop_quit(data->loop);
     60  }
     61  return !done;
    7462}
    7563
    7664int call_filter(const char *const *argv, const char *in, char **out, int *status)
    7765{
    78   int err;
    7966  GPid child_pid;
    8067  int child_stdin, child_stdout;
     
    8976  }
    9077
    91   err = send_receive(child_stdout, child_stdin, in, out);
    92   if (err == 0) {
    93     waitpid(child_pid, status, 0);
    94   }
    95   return err;
     78  if (in == NULL) in = "";
     79  GMainContext *context = g_main_context_new();
     80  struct filter_data data = {&in, in + strlen(in), g_string_new(""), g_main_loop_new(context, FALSE), 0};
     81
     82  GIOChannel *channel = g_io_channel_unix_new(child_stdin);
     83  g_io_channel_set_encoding(channel, NULL, NULL);
     84  g_io_channel_set_flags(channel, g_io_channel_get_flags(channel) | G_IO_FLAG_NONBLOCK, NULL);
     85  GSource *source = g_io_create_watch(channel, G_IO_OUT | G_IO_ERR | G_IO_HUP);
     86  g_io_channel_unref(channel);
     87  g_source_set_callback(source, (GSourceFunc)filter_stdin, &data, NULL);
     88  g_source_attach(source, context);
     89  g_source_unref(source);
     90
     91  channel = g_io_channel_unix_new(child_stdout);
     92  g_io_channel_set_encoding(channel, NULL, NULL);
     93  g_io_channel_set_flags(channel, g_io_channel_get_flags(channel) | G_IO_FLAG_NONBLOCK, NULL);
     94  source = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
     95  g_io_channel_unref(channel);
     96  g_source_set_callback(source, (GSourceFunc)filter_stdout, &data, NULL);
     97  g_source_attach(source, context);
     98  g_source_unref(source);
     99
     100  g_main_loop_run(data.loop);
     101
     102  g_main_loop_unref(data.loop);
     103  g_main_context_unref(context);
     104
     105  waitpid(child_pid, status, 0);
     106  g_spawn_close_pid(child_pid);
     107  *out = g_string_free(data.out_str, data.err);
     108  return data.err;
    96109}
  • functions.c

    rb61ad80 r9e596f5  
    170170    "':sub @b(class)', and then type ':zwrite -c @b(class)' to send.\n\n"
    171171#endif
    172     "@b(AIM:)\n"
    173     "Log in to AIM with ':aimlogin @b(screenname)'. Use ':aimwrite @b(screenname)',\n"
    174     "or 'a' and then the screen name, to send someone a message.\n\n"
    175172    ;
    176173
     
    239236}
    240237
    241 /* Create an outgoing AIM message, returns a pointer to the created
    242  * message or NULL if we're not logged into AIM (and thus unable to
    243  * create the message).  Does not put it on the global queue.  Use
    244  * owl_global_messagequeue_addmsg() for that.
    245  */
    246 CALLER_OWN owl_message *owl_function_make_outgoing_aim(const char *body, const char *to)
    247 {
    248   owl_message *m;
    249 
    250   /* error if we're not logged into aim */
    251   if (!owl_global_is_aimloggedin(&g)) return(NULL);
    252  
    253   m=g_slice_new(owl_message);
    254   owl_message_create_aim(m,
    255                          owl_global_get_aim_screenname(&g),
    256                          to,
    257                          body,
    258                          OWL_MESSAGE_DIRECTION_OUT,
    259                          0);
    260   return(m);
    261 }
    262 
    263238/* Create an outgoing loopback message and return a pointer to it.
    264239 * Does not append it to the global queue, use
     
    325300}
    326301
    327 void owl_function_aimwrite_setup(const char *to)
    328 {
    329   owl_editwin *e;
    330   /* TODO: We probably actually want an owl_aimwrite object like
    331    * owl_zwrite. */
    332   char *line = g_strdup_printf("aimwrite %s", to);
    333   owl_function_write_setup("message");
    334   e = owl_function_start_edit_win(line);
    335   owl_editwin_set_cbdata(e, g_strdup(to), g_free);
    336   owl_editwin_set_callback(e, &owl_callback_aimwrite);
    337   g_free(line);
    338 }
    339 
    340302void owl_function_loopwrite_setup(void)
    341303{
     
    436398  g_free(cryptmsg);
    437399  g_free(old_msg);
    438 }
    439 
    440 void owl_callback_aimwrite(owl_editwin *e, bool success)
    441 {
    442   if (!success) return;
    443   char *to = owl_editwin_get_cbdata(e);
    444   owl_function_aimwrite(to, owl_editwin_get_text(e), true);
    445 }
    446 
    447 void owl_function_aimwrite(const char *to, const char *msg, bool unwrap)
    448 {
    449   int ret;
    450   char *format_msg;
    451   owl_message *m;
    452 
    453   /* make a formatted copy of the message */
    454   format_msg = g_strdup(msg);
    455   if (unwrap)
    456     owl_text_wordunwrap(format_msg);
    457  
    458   /* send the message */
    459   ret=owl_aim_send_im(to, format_msg);
    460   if (!ret) {
    461     owl_function_makemsg("AIM message sent.");
    462   } else {
    463     owl_function_error("Could not send AIM message.");
    464   }
    465 
    466   /* create the outgoing message */
    467   m=owl_function_make_outgoing_aim(msg, to);
    468 
    469   if (m) {
    470     owl_global_messagequeue_addmsg(&g, m);
    471   } else {
    472     owl_function_error("Could not create outgoing AIM message");
    473   }
    474 
    475   g_free(format_msg);
    476 }
    477 
    478 void owl_function_send_aimawymsg(const char *to, const char *msg)
    479 {
    480   int ret;
    481   char *format_msg;
    482   owl_message *m;
    483 
    484   /* make a formatted copy of the message */
    485   format_msg=g_strdup(msg);
    486   owl_text_wordunwrap(format_msg);
    487  
    488   /* send the message */
    489   ret=owl_aim_send_awaymsg(to, format_msg);
    490   if (!ret) {
    491     /* owl_function_makemsg("AIM message sent."); */
    492   } else {
    493     owl_function_error("Could not send AIM message.");
    494   }
    495 
    496   /* create the message */
    497   m=owl_function_make_outgoing_aim(msg, to);
    498   if (m) {
    499     owl_global_messagequeue_addmsg(&g, m);
    500   } else {
    501     owl_function_error("Could not create AIM message");
    502   }
    503   g_free(format_msg);
    504400}
    505401
     
    918814}
    919815
    920 void owl_callback_aimlogin(owl_editwin *e, bool success)
    921 {
    922   if (!success) return;
    923   char *user = owl_editwin_get_cbdata(e);
    924   owl_function_aimlogin(user,
    925                         owl_editwin_get_text(e));
    926 }
    927 
    928 void owl_function_aimlogin(const char *user, const char *passwd) {
    929   int ret;
    930 
    931   /* clear the buddylist */
    932   owl_buddylist_clear(owl_global_get_buddylist(&g));
    933 
    934   /* try to login */
    935   ret=owl_aim_login(user, passwd);
    936   if (ret) owl_function_makemsg("Warning: login for %s failed.\n", user);
    937 }
    938 
    939816void owl_function_suspend(void)
    940817{
     
    969846}
    970847
    971 void owl_function_aaway_toggle(void)
    972 {
    973   if (!owl_global_is_aaway(&g)) {
    974     owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
    975     owl_function_aaway_on();
    976   } else {
    977     owl_function_aaway_off();
    978   }
    979 }
    980 
    981 void owl_function_aaway_on(void)
    982 {
    983   owl_global_set_aaway_on(&g);
    984   /* owl_aim_set_awaymsg(owl_global_get_zaway_msg(&g)); */
    985   owl_function_makemsg("AIM away set (%s)", owl_global_get_aaway_msg(&g));
    986 }
    987 
    988 void owl_function_aaway_off(void)
    989 {
    990   owl_global_set_aaway_off(&g);
    991   /* owl_aim_set_awaymsg(""); */
    992   owl_function_makemsg("AIM away off");
    993 }
    994 
    995848bool owl_function_is_away(void)
    996849{
    997850  return owl_global_is_zaway(&g) ||
    998          owl_global_is_aaway(&g) ||
    999851         owl_perlconfig_perl_call_bool("BarnOwl::Hooks::_get_is_away", 0, NULL);
    1000852}
     
    1017869  if (owl_global_get_newmsgproc_pid(&g)) {
    1018870    kill(owl_global_get_newmsgproc_pid(&g), SIGHUP);
    1019   }
    1020  
    1021   /* Quit AIM */
    1022   if (owl_global_is_aimloggedin(&g)) {
    1023     owl_aim_logout();
    1024871  }
    1025872
     
    12261073  FILE *file;
    12271074  time_t now;
     1075  struct tm tm;
    12281076  va_list ap;
    12291077
     
    12371085  now = time(NULL);
    12381086
    1239   tmpbuff = owl_util_format_time(localtime(&now));
     1087  tmpbuff = owl_util_format_time(localtime_r(&now, &tm));
    12401088  fprintf(file, "[%d -  %s - %lds]: ",
    12411089          (int) getpid(), tmpbuff, now - owl_global_get_starttime(&g));
     
    17751623  char buff[MAXPATHLEN+1];
    17761624  time_t start;
     1625  struct tm tm;
    17771626  int up, days, hours, minutes;
    17781627  owl_fmtext fm;
     
    18001649  owl_fmtext_append_normal(&fm, "\n");
    18011650
    1802   tmpbuff = owl_util_format_time(localtime(&start));
     1651  tmpbuff = owl_util_format_time(localtime_r(&start, &tm));
    18031652  owl_fmtext_appendf_normal(&fm, "  Startup Time: %s\n", tmpbuff);
    18041653  g_free(tmpbuff);
     
    18201669    owl_fmtext_append_normal(&fm, "no\n");
    18211670  }
    1822   owl_fmtext_append_normal(&fm, "  AIM included       : yes\n");
    18231671  owl_fmtext_append_normal(&fm, "  Loopback included  : yes\n");
    18241672
     
    18311679  owl_fmtext_append_normal(&fm, "no\n");
    18321680#endif
    1833  
    1834 
    1835   owl_fmtext_append_normal(&fm, "\nAIM Status:\n");
    1836   owl_fmtext_append_normal(&fm, "  Logged in: ");
    1837   if (owl_global_is_aimloggedin(&g)) {
    1838     owl_fmtext_append_normal(&fm, owl_global_get_aim_screenname(&g));
    1839     owl_fmtext_append_normal(&fm, "\n");
    1840   } else {
    1841     owl_fmtext_append_normal(&fm, "(not logged in)\n");
    1842   }
    1843 
    1844   owl_fmtext_append_normal(&fm, "  Processing events: ");
    1845   if (owl_global_is_doaimevents(&g)) {
    1846     owl_fmtext_append_normal(&fm, "yes\n");
    1847   } else {
    1848     owl_fmtext_append_normal(&fm, "no\n");
    1849   }
    18501681
    18511682  owl_function_popless_fmtext(&fm);
     
    21491980  const owl_view *v;
    21501981  int inuse = 0;
     1982  int i = 2;
     1983  int fgcolor = OWL_COLOR_DEFAULT;
     1984  bool set_fgcolor = false;
     1985  int bgcolor = OWL_COLOR_DEFAULT;
     1986  bool set_bgcolor = false;
    21511987
    21521988  if (argc < 2) {
     
    21652001  }
    21662002
    2167   /* deal with the case of trying change the filter color */
    2168   if (argc==4 && !strcmp(argv[2], "-c")) {
     2003  /* set the color */
     2004  while (i + 2 <= argc && (!strcmp(argv[i], "-c") ||
     2005                           !strcmp(argv[i], "-b"))) {
     2006    int color = owl_util_string_to_color(argv[i + 1]);
     2007    if (color == OWL_COLOR_INVALID) {
     2008      owl_function_error("The color '%s' is not available.", argv[i + 1]);
     2009    } else if (argv[i][1] == 'c') {
     2010      fgcolor = color;
     2011      set_fgcolor = true;
     2012    } else {
     2013      bgcolor = color;
     2014      set_bgcolor = true;
     2015    }
     2016    i += 2;
     2017  }
     2018
     2019  if (i > 2 && i == argc) {
    21692020    f=owl_global_get_filter(&g, argv[1]);
    21702021    if (!f) {
     
    21722023      return false;
    21732024    }
    2174     if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
    2175       owl_function_error("The color '%s' is not available.", argv[3]);
     2025    if (!set_fgcolor && !set_bgcolor)
    21762026      return false;
    2177     }
    2178     owl_filter_set_fgcolor(f, owl_util_string_to_color(argv[3]));
    2179     owl_mainwin_redisplay(owl_global_get_mainwin(&g));
    2180     return false;
    2181   }
    2182   if (argc==4 && !strcmp(argv[2], "-b")) {
    2183     f=owl_global_get_filter(&g, argv[1]);
    2184     if (!f) {
    2185       owl_function_error("The filter '%s' does not exist.", argv[1]);
    2186       return false;
    2187     }
    2188     if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
    2189       owl_function_error("The color '%s' is not available.", argv[3]);
    2190       return false;
    2191     }
    2192     owl_filter_set_bgcolor(f, owl_util_string_to_color(argv[3]));
     2027    if (set_fgcolor)
     2028      owl_filter_set_fgcolor(f, fgcolor);
     2029    if (set_bgcolor)
     2030      owl_filter_set_bgcolor(f, bgcolor);
    21932031    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
    21942032    return true;
     
    21962034
    21972035  /* create the filter and check for errors */
    2198   f = owl_filter_new(argv[1], argc-2, argv+2);
     2036  f = owl_filter_new_colored(argv[1], argc - i, argv + i, fgcolor, bgcolor);
    21992037  if (f == NULL) {
    22002038    owl_function_error("Invalid filter: %s", argv[1]);
     
    24442282  if (f == NULL) {
    24452283    /* Couldn't make a filter for some reason. Return NULL. */
    2446     owl_function_error("Error creating filter '%s'", filtname);
    2447     g_free(filtname);
    2448     return NULL;
    2449   }
    2450 
    2451   /* add it to the global list */
    2452   owl_global_add_filter(&g, f);
    2453 
    2454   return(filtname);
    2455 }
    2456 
    2457 /* Create a filter for AIM IM messages to or from the specified
    2458  * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
    2459  * filter already exists with this name, no new filter will be
    2460  * created.  This allows the configuration to override this function.
    2461  * Returns the name of the filter, which the caller must free.
    2462  */
    2463 CALLER_OWN char *owl_function_aimuserfilt(const char *user)
    2464 {
    2465   owl_filter *f;
    2466   char *argbuff, *filtname;
    2467   char *escuser;
    2468 
    2469   /* name for the filter */
    2470   filtname=g_strdup_printf("aimuser-%s", user);
    2471 
    2472   /* if it already exists then go with it.  This lets users override */
    2473   if (owl_global_get_filter(&g, filtname)) {
    2474     return filtname;
    2475   }
    2476 
    2477   /* create the new-internal filter */
    2478   escuser = owl_text_quote(user, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
    2479 
    2480   argbuff = g_strdup_printf(
    2481       "( type ^aim$ and ( ( sender ^%1$s$ and recipient ^%2$s$ ) or "
    2482       "( sender ^%2$s$ and recipient ^%1$s$ ) ) )",
    2483       escuser, owl_global_get_aim_screenname_for_filters(&g));
    2484   g_free(escuser);
    2485 
    2486   f = owl_filter_new_fromstring(filtname, argbuff);
    2487   g_free(argbuff);
    2488 
    2489   if (f == NULL) {
    24902284    owl_function_error("Error creating filter '%s'", filtname);
    24912285    g_free(filtname);
     
    26042398 * If the curmsg is a zephyr class message and type==1 then
    26052399 *    return a filter name for the class and instance.
    2606  * If the curmsg is a personal AIM message returna  filter
    2607  *    name to the AIM conversation with that user
    26082400 */
    26092401CALLER_OWN char *owl_function_smartfilter(int type, int invert_related)
     
    26312423  if (owl_message_is_type_loopback(m)) {
    26322424    return(owl_function_typefilt("loopback"));
    2633   }
    2634 
    2635   /* aim messages */
    2636   if (owl_message_is_type_aim(m)) {
    2637     if (owl_message_is_direction_in(m)) {
    2638       filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
    2639     } else if (owl_message_is_direction_out(m)) {
    2640       filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
    2641     }
    2642     return(filtname);
    26432425  }
    26442426
     
    30682850
    30692851/* Popup a buddylisting.  If filename is NULL use the default .anyone */
    3070 void owl_function_buddylist(int aim, int zephyr, const char *filename)
    3071 {
    3072   int i, j, idle;
     2852void owl_function_buddylist(int zephyr, const char *filename)
     2853{
     2854  int i;
    30732855  int interrupted = 0;
    30742856  owl_fmtext fm;
    3075   const owl_buddylist *bl;
    3076   const owl_buddy *b;
    3077   char *timestr;
    30782857#ifdef HAVE_LIBZEPHYR
    30792858  int x;
     
    30862865
    30872866  owl_fmtext_init_null(&fm);
    3088 
    3089   /* AIM first */
    3090   if (aim && owl_global_is_aimloggedin(&g)) {
    3091     bl=owl_global_get_buddylist(&g);
    3092 
    3093     owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
    3094     /* we're assuming AIM for now */
    3095     j=owl_buddylist_get_size(bl);
    3096     for (i=0; i<j; i++) {
    3097       b=owl_buddylist_get_buddy_n(bl, i);
    3098       idle=owl_buddy_get_idle_time(b);
    3099       if (idle!=0) {
    3100         timestr=owl_util_format_minutes(idle);
    3101       } else {
    3102         timestr=g_strdup("");
    3103       }
    3104       owl_fmtext_appendf_normal(&fm, "  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
    3105       g_free(timestr);
    3106     }
    3107   }
    31082867
    31092868#ifdef HAVE_LIBZEPHYR
     
    31622921#endif
    31632922
    3164   if (aim && zephyr) {
     2923  if (zephyr) {
    31652924    if (owl_perlconfig_is_function("BarnOwl::Hooks::_get_blist")) {
    31662925      char * perlblist = owl_perlconfig_execute("BarnOwl::Hooks::_get_blist()");
     
    34243183  char *date;
    34253184  time_t now;
     3185  struct tm tm;
    34263186  char *buff;
    34273187
    34283188  now = time(NULL);
    3429   date = owl_util_format_time(localtime(&now));
     3189  date = owl_util_format_time(localtime_r(&now, &tm));
    34303190
    34313191  buff = g_strdup_printf("%s %s", date, string);
     
    35053265}
    35063266
    3507 void owl_function_aimsearch_results(const char *email, GPtrArray *namelist)
    3508 {
    3509   owl_fmtext fm;
    3510   int i;
    3511 
    3512   owl_fmtext_init_null(&fm);
    3513   owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
    3514   owl_fmtext_append_normal(&fm, email);
    3515   owl_fmtext_append_normal(&fm, ":\n");
    3516 
    3517   for (i = 0; i < namelist->len; i++) {
    3518     owl_fmtext_append_normal(&fm, "  ");
    3519     owl_fmtext_append_normal(&fm, namelist->pdata[i]);
    3520     owl_fmtext_append_normal(&fm, "\n");
    3521   }
    3522 
    3523   owl_function_popless_fmtext(&fm);
    3524   owl_fmtext_cleanup(&fm);
    3525 }
    3526 
    35273267int owl_function_get_color_count(void)
    35283268{
  • global.c

    r7dcef03 r4fd3c04  
    8484  _owl_global_init_windows(g);
    8585
    86   g->aim_screenname=NULL;
    87   g->aim_screenname_for_filters=NULL;
    88   g->aim_loggedin=0;
    89   owl_buddylist_init(&(g->buddylist));
    90 
    9186  g->havezephyr=0;
    92   g->haveaim=0;
    93   g->ignoreaimlogin=0;
    94   owl_global_set_no_doaimevents(g);
    9587
    9688  owl_errqueue_init(&(g->errqueue));
     
    646638}
    647639
    648 /* AIM stuff */
    649 
    650 int owl_global_is_aimloggedin(const owl_global *g)
    651 {
    652   if (g->aim_loggedin) return(1);
    653   return(0);
    654 }
    655 
    656 const char *owl_global_get_aim_screenname(const owl_global *g)
    657 {
    658   if (owl_global_is_aimloggedin(g)) {
    659     return (g->aim_screenname);
    660   }
    661   return("");
    662 }
    663 
    664 const char *owl_global_get_aim_screenname_for_filters(const owl_global *g)
    665 {
    666   if (owl_global_is_aimloggedin(g)) {
    667     return (g->aim_screenname_for_filters);
    668   }
    669   return("");
    670 }
    671 
    672 void owl_global_set_aimloggedin(owl_global *g, const char *screenname)
    673 {
    674   char *sn_escaped;
    675   g->aim_loggedin=1;
    676   if (g->aim_screenname) g_free(g->aim_screenname);
    677   if (g->aim_screenname_for_filters) g_free(g->aim_screenname_for_filters);
    678   g->aim_screenname=g_strdup(screenname);
    679   sn_escaped = owl_text_quote(screenname, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
    680   g->aim_screenname_for_filters = owl_arg_quote(sn_escaped);
    681   g_free(sn_escaped);
    682 }
    683 
    684 void owl_global_set_aimnologgedin(owl_global *g)
    685 {
    686   g->aim_loggedin=0;
    687 }
    688 
    689 bool owl_global_is_doaimevents(const owl_global *g)
    690 {
    691   return g->aim_event_source != NULL;
    692 }
    693 
    694 void owl_global_set_doaimevents(owl_global *g)
    695 {
    696   if (g->aim_event_source)
    697     return;
    698   g->aim_event_source = owl_aim_event_source_new(owl_global_get_aimsess(g));
    699   g_source_attach(g->aim_event_source, NULL);
    700 }
    701 
    702 void owl_global_set_no_doaimevents(owl_global *g)
    703 {
    704   if (!g->aim_event_source)
    705     return;
    706   g_source_destroy(g->aim_event_source);
    707   g_source_unref(g->aim_event_source);
    708   g->aim_event_source = NULL;
    709 }
    710 
    711 aim_session_t *owl_global_get_aimsess(owl_global *g)
    712 {
    713   return(&(g->aimsess));
    714 }
    715 
    716 aim_conn_t *owl_global_get_bosconn(owl_global *g)
    717 {
    718   return(&(g->bosconn));
    719 }
    720 
    721 void owl_global_set_bossconn(owl_global *g, aim_conn_t *conn)
    722 {
    723   g->bosconn=*conn;
    724 }
    725 
    726640/* message queue */
    727641
     
    750664}
    751665
    752 owl_buddylist *owl_global_get_buddylist(owl_global *g)
    753 {
    754   return(&(g->buddylist));
    755 }
    756  
    757666/* style */
    758667
     
    781690  owl_dict_insert_element(&(g->styledict), owl_style_get_name(s),
    782691                          s, (void (*)(void *))owl_style_delete);
    783 }
    784 
    785 void owl_global_set_haveaim(owl_global *g)
    786 {
    787   g->haveaim=1;
    788 }
    789 
    790 int owl_global_is_haveaim(const owl_global *g)
    791 {
    792   if (g->haveaim) return(1);
    793   return(0);
    794 }
    795 
    796 void owl_global_set_ignore_aimlogin(owl_global *g)
    797 {
    798     g->ignoreaimlogin = 1;
    799 }
    800 
    801 void owl_global_unset_ignore_aimlogin(owl_global *g)
    802 {
    803     g->ignoreaimlogin = 0;
    804 }
    805 
    806 int owl_global_is_ignore_aimlogin(const owl_global *g)
    807 {
    808     return g->ignoreaimlogin;
    809692}
    810693
     
    867750    { "reply-lockout", "class ^mail$ or class ^filsrv$" },
    868751    { "out", "direction ^out$" },
    869     { "aim", "type ^aim$" },
    870752    { "zephyr", "type ^zephyr$" },
    871753    { "none", "false" },
  • help.c

    r8258ea5 r4fd3c04  
    5252     "\n"
    5353     "    z             Start a zwrite command\n"
    54      "    a             Start an aimwrite command\n"
    5554     "    r             Reply to the current message\n"
    5655     "    R             Reply to sender\n"
     
    6463     "    !             Invert the current view\n"
    6564     "\n"
    66      "    l             Print a zephyr/AIM buddy listing\n"
     65     "    l             Print a zephyr buddy listing\n"
    6766     "    A             Toggle away\n"
    6867     "    o             Toggle one-line display mode\n"
     
    8887     "\n"
    8988     "    zwrite        Send a zephyr\n"
    90      "    aimlogin      Login to AIM\n"
    91      "    aimwrite      Send an AIM message\n"
    9289     "\n"
    93      "    addbuddy      Add a zephyr or AIM buddy\n"
     90     "    addbuddy      Add a zephyr buddy\n"
    9491     "    zaway         Turn zaway on or off, or set the message\n"
    9592     "    zlocate       Locate a user\n"
    9693     "    subscribe     Subscribe to a zephyr class or instance\n"
    9794     "    unsubscribe   Unsubscribe to a zephyr class or instance\n"
    98      "    blist         Print a list of zephyr and AIM buddies logged in\n"
     95     "    blist         Print a list of zephyr buddies logged in\n"
    9996     "    search        Search for a text string\n"
    10097     "\n"
     
    110107     "    zlog          Send a login or logout notification\n"
    111108     "    zlist         Print a list of zephyr buddies logged in\n"
    112      "    alist         Print a list of AIM buddies logged in\n"
    113109     "    info          Print detailed information about the current message\n"
    114110     "    filter        Create a message filter\n"
  • keys.c

    rdcd48ad r4fd3c04  
    4444  BIND_CMD("M-RIGHT",     "edit:move-next-word", "");
    4545  BIND_CMD("M-[ 1 ; 3 D", "edit:move-next-word", "");
     46  BIND_CMD("M-[ 1 ; 5 D", "edit:move-next-word", "");
    4647  BIND_CMD("M-b",         "edit:move-prev-word", "");
    4748  BIND_CMD("M-O 3 D",     "edit:move-prev-word", "");
    4849  BIND_CMD("M-LEFT",      "edit:move-prev-word", "");
    49   BIND_CMD("M-[ 1 ; 3 C", "edit:move-next-word", "");
     50  BIND_CMD("M-[ 1 ; 3 C", "edit:move-prev-word", "");
     51  BIND_CMD("M-[ 1 ; 5 C", "edit:move-prev-word", "");
    5052
    5153  BIND_CMD("LEFT",        "edit:move-left", "");
     
    315317
    316318  BIND_CMD("z",   "start-command zwrite ", "start a zwrite command");
    317   BIND_CMD("a",   "start-command aimwrite ", "start an aimwrite command");
    318319  BIND_CMD("r",   "reply",            "reply to the current message");
    319320  BIND_CMD("R",   "reply sender",     "reply to sender of the current message");
  • logging.c

    r7dcef03 r0c059f0  
    77} owl_log_entry;
    88
     9typedef struct _owl_log_options { /* noproto */
     10  bool drop_failed_logs;
     11  bool display_initial_log_count;
     12} owl_log_options;
    913
    1014static GMainContext *log_context;
    1115static GMainLoop *log_loop;
    1216static GThread *logging_thread;
    13 
    14 /* This is now the one function that should be called to log a
    15  * message.  It will do all the work necessary by calling the other
    16  * functions in this file as necessary.
     17static bool defer_logs; /* to be accessed only on the disk-writing thread */
     18static GQueue *deferred_entry_queue;
     19
     20static void owl_log_error_main_thread(gpointer data)
     21{
     22  owl_function_error("%s", (const char*)data);
     23}
     24
     25static void owl_log_adminmsg_main_thread(gpointer data)
     26{
     27  owl_function_adminmsg("Logging", (const char*)data);
     28}
     29
     30static void owl_log_makemsg_main_thread(gpointer data)
     31{
     32  owl_function_makemsg("%s", (const char*)data);
     33}
     34
     35static void G_GNUC_PRINTF(1, 2) owl_log_error(const char *fmt, ...)
     36{
     37  va_list ap;
     38  char *data;
     39
     40  va_start(ap, fmt);
     41  data = g_strdup_vprintf(fmt, ap);
     42  va_end(ap);
     43
     44  owl_select_post_task(owl_log_error_main_thread,
     45                       data, g_free, g_main_context_default());
     46}
     47
     48static void G_GNUC_PRINTF(1, 2) owl_log_adminmsg(const char *fmt, ...)
     49{
     50  va_list ap;
     51  char *data;
     52
     53  va_start(ap, fmt);
     54  data = g_strdup_vprintf(fmt, ap);
     55  va_end(ap);
     56
     57  owl_select_post_task(owl_log_adminmsg_main_thread,
     58                       data, g_free, g_main_context_default());
     59}
     60
     61static void G_GNUC_PRINTF(1, 2) owl_log_makemsg(const char *fmt, ...)
     62{
     63  va_list ap;
     64  char *data;
     65
     66  va_start(ap, fmt);
     67  data = g_strdup_vprintf(fmt, ap);
     68  va_end(ap);
     69
     70  owl_select_post_task(owl_log_makemsg_main_thread,
     71                       data, g_free, g_main_context_default());
     72}
     73
     74static CALLER_OWN owl_log_entry *owl_log_new_entry(const char *buffer, const char *filename)
     75{
     76  owl_log_entry *log_msg = g_slice_new(owl_log_entry);
     77  log_msg->message = g_strdup(buffer);
     78  log_msg->filename = g_strdup(filename);
     79  return log_msg;
     80}
     81
     82static void owl_log_deferred_enqueue_message(const char *buffer, const char *filename)
     83{
     84  g_queue_push_tail(deferred_entry_queue, owl_log_new_entry(buffer, filename));
     85}
     86
     87static void owl_log_deferred_enqueue_first_message(const char *buffer, const char *filename)
     88{
     89  g_queue_push_head(deferred_entry_queue, owl_log_new_entry(buffer, filename));
     90}
     91
     92/* write out the entry if possible
     93 * return 0 on success, errno on failure to open
    1794 */
    18 void owl_log_message(const owl_message *m) {
    19   owl_function_debugmsg("owl_log_message: entering");
    20 
    21   if (m == NULL) {
    22     owl_function_debugmsg("owl_log_message: passed null message");
    23     return;
    24   }
    25 
    26   /* should we be logging this message? */
    27   if (!owl_log_shouldlog_message(m)) {
    28     owl_function_debugmsg("owl_log_message: not logging message");
    29     return;
    30   }
    31 
    32   /* handle incmoing messages */
    33   if (owl_message_is_direction_in(m)) {
    34     owl_log_incoming(m);
    35     owl_function_debugmsg("owl_log_message: leaving");
    36     return;
    37   }
    38 
    39   /* handle outgoing messages */
    40   owl_log_outgoing(m);
    41 
    42   owl_function_debugmsg("owl_log_message: leaving");
    43 }
    44 
    45 /* Return 1 if we should log the given message, otherwise return 0 */
    46 int owl_log_shouldlog_message(const owl_message *m) {
    47   const owl_filter *f;
    48 
    49   /* If there's a logfilter and this message matches it, log */
    50   f=owl_global_get_filter(&g, owl_global_get_logfilter(&g));
    51   if (f && owl_filter_message_match(f, m)) return(1);
    52 
    53   /* otherwise we do things based on the logging variables */
    54 
    55   /* skip login/logout messages if appropriate */
    56   if (!owl_global_is_loglogins(&g) && owl_message_is_loginout(m)) return(0);
    57      
    58   /* check direction */
    59   if ((owl_global_get_loggingdirection(&g)==OWL_LOGGING_DIRECTION_IN) && owl_message_is_direction_out(m)) {
    60     return(0);
    61   }
    62   if ((owl_global_get_loggingdirection(&g)==OWL_LOGGING_DIRECTION_OUT) && owl_message_is_direction_in(m)) {
    63     return(0);
    64   }
    65 
    66   if (owl_message_is_type_zephyr(m)) {
    67     if (owl_message_is_personal(m) && !owl_global_is_logging(&g)) return(0);
    68     if (!owl_message_is_personal(m) && !owl_global_is_classlogging(&g)) return(0);
    69   } else {
    70     if (owl_message_is_private(m) || owl_message_is_loginout(m)) {
    71       if (!owl_global_is_logging(&g)) return(0);
    72     } else {
    73       if (!owl_global_is_classlogging(&g)) return(0);
    74     }
    75   }
    76   return(1);
    77 }
    78 
    79 CALLER_OWN char *owl_log_zephyr(const owl_message *m)
    80 {
    81     char *tmp = NULL;
    82     GString *buffer = NULL;
    83     buffer = g_string_new("");
    84     tmp = short_zuser(owl_message_get_sender(m));
    85     g_string_append_printf(buffer, "Class: %s Instance: %s",
    86                            owl_message_get_class(m),
    87                            owl_message_get_instance(m));
    88     if (strcmp(owl_message_get_opcode(m), "")) {
    89       g_string_append_printf(buffer, " Opcode: %s",
    90                              owl_message_get_opcode(m));
    91     }
    92     g_string_append_printf(buffer, "\n");
    93     g_string_append_printf(buffer, "Time: %s Host: %s\n",
    94                            owl_message_get_timestr(m),
    95                            owl_message_get_hostname(m));
    96     g_string_append_printf(buffer, "From: %s <%s>\n\n",
    97                            owl_message_get_zsig(m), tmp);
    98     g_string_append_printf(buffer, "%s\n\n", owl_message_get_body(m));
    99     g_free(tmp);
    100     return g_string_free(buffer, FALSE);
    101 }
    102 
    103 CALLER_OWN char *owl_log_aim(const owl_message *m)
    104 {
    105     GString *buffer = NULL;
    106     buffer = g_string_new("");
    107     g_string_append_printf(buffer, "From: <%s> To: <%s>\n",
    108                            owl_message_get_sender(m), owl_message_get_recipient(m));
    109     g_string_append_printf(buffer, "Time: %s\n\n",
    110                            owl_message_get_timestr(m));
    111     if (owl_message_is_login(m)) {
    112         g_string_append_printf(buffer, "LOGIN\n\n");
    113     } else if (owl_message_is_logout(m)) {
    114         g_string_append_printf(buffer, "LOGOUT\n\n");
    115     } else {
    116         g_string_append_printf(buffer, "%s\n\n", owl_message_get_body(m));
    117     }
    118     return g_string_free(buffer, FALSE);
    119 }
    120 
    121 CALLER_OWN char *owl_log_jabber(const owl_message *m)
    122 {
    123     GString *buffer = NULL;
    124     buffer = g_string_new("");
    125     g_string_append_printf(buffer, "From: <%s> To: <%s>\n",
    126                            owl_message_get_sender(m),
    127                            owl_message_get_recipient(m));
    128     g_string_append_printf(buffer, "Time: %s\n\n",
    129                            owl_message_get_timestr(m));
    130     g_string_append_printf(buffer, "%s\n\n", owl_message_get_body(m));
    131     return g_string_free(buffer, FALSE);
    132 }
    133 
    134 CALLER_OWN char *owl_log_generic(const owl_message *m)
    135 {
    136     GString *buffer;
    137     buffer = g_string_new("");
    138     g_string_append_printf(buffer, "From: <%s> To: <%s>\n",
    139                            owl_message_get_sender(m),
    140                            owl_message_get_recipient(m));
    141     g_string_append_printf(buffer, "Time: %s\n\n",
    142                            owl_message_get_timestr(m));
    143     g_string_append_printf(buffer, "%s\n\n",
    144                            owl_message_get_body(m));
    145     return g_string_free(buffer, FALSE);
    146 }
    147 
    148 static void owl_log_error_main_thread(gpointer data)
    149 {
    150   owl_function_error("%s", (const char*)data);
    151 }
    152 
    153 static void owl_log_error(const char *message)
    154 {
    155   char *data = g_strdup(message);
    156   owl_select_post_task(owl_log_error_main_thread,
    157                        data, g_free, g_main_context_default());
    158 }
    159 
    160 static void owl_log_write_entry(gpointer data)
    161 {
    162   owl_log_entry *msg = (owl_log_entry*)data;
     95static int owl_log_try_write_entry(owl_log_entry *msg)
     96{
    16397  FILE *file = NULL;
    16498  file = fopen(msg->filename, "a");
    16599  if (!file) {
    166     owl_log_error("Unable to open file for logging");
    167     return;
     100    return errno;
    168101  }
    169102  fprintf(file, "%s", msg->message);
    170103  fclose(file);
    171 }
    172 
    173 static void owl_log_entry_free(void *data)
     104  return 0;
     105}
     106
     107static void owl_log_entry_delete(void *data)
    174108{
    175109  owl_log_entry *msg = (owl_log_entry*)data;
    176   if (msg) {
    177     g_free(msg->message);
    178     g_free(msg->filename);
    179     g_slice_free(owl_log_entry, msg);
    180   }
     110  g_free(msg->message);
     111  g_free(msg->filename);
     112  g_slice_free(owl_log_entry, msg);
     113}
     114
     115#if GLIB_CHECK_VERSION(2, 32, 0)
     116#else
     117static void owl_log_entry_delete_gfunc(gpointer data, gpointer user_data)
     118{
     119  owl_log_entry_delete(data);
     120}
     121#endif
     122
     123static void owl_log_file_error(owl_log_entry *msg, int errnum)
     124{
     125  owl_log_error("Unable to open file for logging: %s (file %s)",
     126                g_strerror(errnum),
     127                msg->filename);
     128}
     129
     130/* If we are deferring log messages, enqueue this entry for writing.
     131 * Otherwise, try to write this log message, and, if it fails with
     132 * EPERM, EACCES, or ETIMEDOUT, go into deferred logging mode and
     133 * queue an admin message.  If it fails with anything else, display an
     134 * error message, drop the log message, and do not go into deferred
     135 * logging mode.
     136 *
     137 * N.B. This function is called only on the disk-writing thread. */
     138static void owl_log_eventually_write_entry(gpointer data)
     139{
     140  int ret;
     141  owl_log_entry *msg = (owl_log_entry*)data;
     142  if (defer_logs) {
     143    owl_log_deferred_enqueue_message(msg->message, msg->filename);
     144  } else {
     145    ret = owl_log_try_write_entry(msg);
     146    if (ret == EPERM || ret == EACCES || ret == ETIMEDOUT) {
     147      defer_logs = true;
     148      owl_log_error("Unable to open file for logging (%s): \n"
     149                    "%s.  \n"
     150                    "Consider renewing your tickets.  Logging has been \n"
     151                    "suspended, and your messages will be saved.  To \n"
     152                    "resume logging, use the command :flush-logs.\n\n",
     153                    msg->filename,
     154                    g_strerror(ret));
     155      /* If we were not in deferred logging mode, either the queue should be
     156       * empty, or we are attempting to log a message that we just popped off
     157       * the head of the queue.  Either way, we should enqueue this message as
     158       * the first message in the queue, rather than the last, so that we
     159       * preserve message ordering. */
     160      owl_log_deferred_enqueue_first_message(msg->message, msg->filename);
     161    } else if (ret != 0) {
     162      owl_log_file_error(msg, ret);
     163    }
     164  }
     165}
     166
     167/* tries to write the deferred log entries
     168 *
     169 * N.B. This function is called only on the disk-writing thread. */
     170static void owl_log_write_deferred_entries(gpointer data)
     171{
     172  owl_log_entry *entry;
     173  owl_log_options *opts = (owl_log_options *)data;
     174  int ret;
     175  int logged_message_count = 0;
     176  bool all_succeeded = true;
     177
     178  if (opts->display_initial_log_count) {
     179    if (g_queue_is_empty(deferred_entry_queue)) {
     180      owl_log_makemsg("There are no logs to flush.");
     181    } else {
     182      owl_log_makemsg("Attempting to flush %u logs...",
     183                      g_queue_get_length(deferred_entry_queue));
     184    }
     185  }
     186
     187  defer_logs = false;
     188  while (!g_queue_is_empty(deferred_entry_queue) && !defer_logs) {
     189    logged_message_count++;
     190    entry = (owl_log_entry*)g_queue_pop_head(deferred_entry_queue);
     191    if (!opts->drop_failed_logs) {
     192      /* Attempt to write the log entry.  If it fails, re-queue the entry at
     193       * the head of the queue. */
     194      owl_log_eventually_write_entry(entry);
     195    } else {
     196      /* Attempt to write the log entry. If it fails, print an error message,
     197       * drop the log, and keep going through the queue. */
     198      ret = owl_log_try_write_entry(entry);
     199      if (ret != 0) {
     200        all_succeeded = false;
     201        owl_log_file_error(entry, ret);
     202      }
     203    }
     204    owl_log_entry_delete(entry);
     205  }
     206  if (logged_message_count > 0) {
     207    if (opts->display_initial_log_count) {
     208      /* first clear the "attempting to flush" message from the status bar */
     209      owl_log_makemsg("");
     210    }
     211    if (!defer_logs) {
     212      if (all_succeeded) {
     213        owl_log_adminmsg("Flushed %d logs and resumed logging.",
     214                         logged_message_count);
     215      } else {
     216        owl_log_adminmsg("Flushed or dropped %d logs and resumed logging.",
     217                         logged_message_count);
     218      }
     219    } else {
     220      owl_log_error("Attempted to flush %d logs; %u deferred logs remain.",
     221                    logged_message_count, g_queue_get_length(deferred_entry_queue));
     222    }
     223  }
     224}
     225
     226void owl_log_flush_logs(bool drop_failed_logs, bool quiet)
     227{
     228  owl_log_options *data = g_new(owl_log_options, 1);
     229  data->drop_failed_logs = drop_failed_logs;
     230  data->display_initial_log_count = !quiet;
     231
     232  owl_select_post_task(owl_log_write_deferred_entries,
     233                       data,
     234                       g_free,
     235                       log_context);
    181236}
    182237
    183238void owl_log_enqueue_message(const char *buffer, const char *filename)
    184239{
    185   owl_log_entry *log_msg = NULL;
    186   log_msg = g_slice_new(owl_log_entry);
    187   log_msg->message = g_strdup(buffer);
    188   log_msg->filename = g_strdup(filename);
    189   owl_select_post_task(owl_log_write_entry, log_msg,
    190                        owl_log_entry_free, log_context);
    191 }
    192 
    193 void owl_log_append(const owl_message *m, const char *filename) {
    194   char *buffer = NULL;
    195   if (owl_message_is_type_zephyr(m)) {
    196     buffer = owl_log_zephyr(m);
    197   } else if (owl_message_is_type_jabber(m)) {
    198     buffer = owl_log_jabber(m);
    199   } else if (owl_message_is_type_aim(m)) {
    200     buffer = owl_log_aim(m);
    201   } else {
    202     buffer = owl_log_generic(m);
    203   }
    204   owl_log_enqueue_message(buffer, filename);
    205   g_free(buffer);
    206 }
    207 
    208 void owl_log_outgoing(const owl_message *m)
    209 {
    210   char *filename, *logpath;
    211   char *to, *temp;
    212   GList *cc;
    213 
    214   /* expand ~ in path names */
    215   logpath = owl_util_makepath(owl_global_get_logpath(&g));
    216 
    217   /* Figure out what path to log to */
    218   if (owl_message_is_type_zephyr(m)) {
    219     /* If this has CC's, do all but the "recipient" which we'll do below */
    220     cc = owl_message_get_cc_without_recipient(m);
    221     while (cc != NULL) {
    222       temp = short_zuser(cc->data);
    223       filename = g_build_filename(logpath, temp, NULL);
    224       owl_log_append(m, filename);
    225 
    226       g_free(filename);
    227       g_free(temp);
    228       g_free(cc->data);
    229       cc = g_list_delete_link(cc, cc);
    230     }
    231 
    232     to = short_zuser(owl_message_get_recipient(m));
    233   } else if (owl_message_is_type_jabber(m)) {
    234     to = g_strdup_printf("jabber:%s", owl_message_get_recipient(m));
    235     g_strdelimit(to, "/", '_');
    236   } else if (owl_message_is_type_aim(m)) {
    237     char *temp2;
    238     temp = owl_aim_normalize_screenname(owl_message_get_recipient(m));
    239     temp2 = g_utf8_strdown(temp,-1);
    240     to = g_strdup_printf("aim:%s", temp2);
    241     g_free(temp2);
    242     g_free(temp);
    243   } else {
    244     to = g_strdup("loopback");
    245   }
    246 
    247   filename = g_build_filename(logpath, to, NULL);
    248   owl_log_append(m, filename);
    249   g_free(to);
    250   g_free(filename);
    251 
    252   filename = g_build_filename(logpath, "all", NULL);
    253   owl_log_append(m, filename);
    254   g_free(logpath);
    255   g_free(filename);
    256 }
    257 
     240  owl_log_entry *log_msg = owl_log_new_entry(buffer, filename);
     241  owl_select_post_task(owl_log_eventually_write_entry, log_msg,
     242                       owl_log_entry_delete, log_context);
     243}
    258244
    259245void owl_log_outgoing_zephyr_error(const owl_zwrite *zw, const char *text)
    260246{
    261   char *filename, *logpath;
    262   char *tobuff, *recip;
    263   owl_message *m;
    264   GString *msgbuf;
    265   /* create a present message so we can pass it to
    266    * owl_log_shouldlog_message(void)
    267    */
    268   m = g_slice_new(owl_message);
     247  owl_message *m = g_slice_new(owl_message);
    269248  /* recip_index = 0 because there can only be one recipient anyway */
    270249  owl_message_create_from_zwrite(m, zw, text, 0);
    271   if (!owl_log_shouldlog_message(m)) {
    272     owl_message_delete(m);
    273     return;
    274   }
     250  g_free(owl_perlconfig_call_with_message("BarnOwl::Logging::log_outgoing_error", m));
    275251  owl_message_delete(m);
    276 
    277   /* chop off a local realm */
    278   recip = owl_zwrite_get_recip_n_with_realm(zw, 0);
    279   tobuff = short_zuser(recip);
    280   g_free(recip);
    281 
    282   /* expand ~ in path names */
    283   logpath = owl_util_makepath(owl_global_get_logpath(&g));
    284   filename = g_build_filename(logpath, tobuff, NULL);
    285   msgbuf = g_string_new("");
    286   g_string_printf(msgbuf, "ERROR (owl): %s\n%s\n", tobuff, text);
    287   if (text[strlen(text)-1] != '\n') {
    288     g_string_append_printf(msgbuf, "\n");
    289   }
    290   owl_log_enqueue_message(msgbuf->str, filename);
    291   g_string_free(msgbuf, TRUE);
    292 
    293   filename = g_build_filename(logpath, "all", NULL);
    294   g_free(logpath);
    295   msgbuf = g_string_new("");
    296   g_string_printf(msgbuf, "ERROR (owl): %s\n%s\n", tobuff, text);
    297   if (text[strlen(text)-1] != '\n') {
    298     g_string_append_printf(msgbuf, "\n");
    299   }
    300   owl_log_enqueue_message(msgbuf->str, filename);
    301   g_string_free(msgbuf, TRUE);
    302 
    303   g_free(tobuff);
    304 }
    305 
    306 void owl_log_incoming(const owl_message *m)
    307 {
    308   char *filename, *allfilename, *logpath;
    309   const char *from=NULL;
    310   char *frombuff=NULL;
    311   int len, ch, i, personal;
    312 
    313   /* figure out if it's a "personal" message or not */
    314   if (owl_message_is_type_zephyr(m)) {
    315     if (owl_message_is_personal(m)) {
    316       personal = 1;
    317     } else {
    318       personal = 0;
    319     }
    320   } else if (owl_message_is_type_jabber(m)) {
    321     /* This needs to be fixed to handle groupchat */
    322     const char* msgtype = owl_message_get_attribute_value(m,"jtype");
    323     if (msgtype && !strcmp(msgtype,"groupchat")) {
    324       personal = 0;
    325     } else {
    326       personal = 1;
    327     }
    328   } else {
    329     if (owl_message_is_private(m) || owl_message_is_loginout(m)) {
    330       personal = 1;
    331     } else {
    332       personal = 0;
    333     }
    334   }
    335 
    336 
    337   if (owl_message_is_type_zephyr(m)) {
    338     if (personal) {
    339       from=frombuff=short_zuser(owl_message_get_sender(m));
    340     } else {
    341       from=frombuff=g_strdup(owl_message_get_class(m));
    342     }
    343   } else if (owl_message_is_type_aim(m)) {
    344     /* we do not yet handle chat rooms */
    345     char *normalto, *temp;
    346     temp = owl_aim_normalize_screenname(owl_message_get_sender(m));
    347     normalto = g_utf8_strdown(temp, -1);
    348     from=frombuff=g_strdup_printf("aim:%s", normalto);
    349     g_free(normalto);
    350     g_free(temp);
    351   } else if (owl_message_is_type_loopback(m)) {
    352     from=frombuff=g_strdup("loopback");
    353   } else if (owl_message_is_type_jabber(m)) {
    354     if (personal) {
    355       from=frombuff=g_strdup_printf("jabber:%s",
    356                                     owl_message_get_sender(m));
    357     } else {
    358       from=frombuff=g_strdup_printf("jabber:%s",
    359                                     owl_message_get_recipient(m));
    360     }
    361   } else {
    362     from=frombuff=g_strdup("unknown");
    363   }
    364  
    365   /* check for malicious sender formats */
    366   len=strlen(frombuff);
    367   if (len<1 || len>35) from="weird";
    368   if (strchr(frombuff, '/')) from="weird";
    369 
    370   ch=frombuff[0];
    371   if (!g_ascii_isalnum(ch)) from="weird";
    372 
    373   for (i=0; i<len; i++) {
    374     if (frombuff[i]<'!' || frombuff[i]>='~') from="weird";
    375   }
    376 
    377   if (!strcmp(frombuff, ".") || !strcasecmp(frombuff, "..")) from="weird";
    378 
    379   if (!personal) {
    380     if (strcmp(from, "weird")) {
    381       char* temp = g_utf8_strdown(frombuff, -1);
    382       if (temp) {
    383         g_free(frombuff);
    384         from = frombuff = temp;
    385       }
    386     }
    387   }
    388 
    389   /* create the filename (expanding ~ in path names) */
    390   if (personal) {
    391     logpath = owl_util_makepath(owl_global_get_logpath(&g));
    392     filename = g_build_filename(logpath, from, NULL);
    393     allfilename = g_build_filename(logpath, "all", NULL);
    394     owl_log_append(m, allfilename);
    395     g_free(allfilename);
    396   } else {
    397     logpath = owl_util_makepath(owl_global_get_classlogpath(&g));
    398     filename = g_build_filename(logpath, from, NULL);
    399   }
    400 
    401   owl_log_append(m, filename);
    402   g_free(filename);
    403 
    404   if (personal && owl_message_is_type_zephyr(m)) {
    405     /* We want to log to all of the CC'd people who were not us, or
    406      * the sender, as well.
    407      */
    408     char *temp;
    409     GList *cc;
    410     cc = owl_message_get_cc_without_recipient(m);
    411     while (cc != NULL) {
    412       temp = short_zuser(cc->data);
    413       if (strcasecmp(temp, frombuff) != 0) {
    414         filename = g_build_filename(logpath, temp, NULL);
    415         owl_log_append(m, filename);
    416         g_free(filename);
    417       }
    418 
    419       g_free(temp);
    420       g_free(cc->data);
    421       cc = g_list_delete_link(cc, cc);
    422     }
    423   }
    424 
    425   g_free(frombuff);
    426   g_free(logpath);
    427252}
    428253
    429254static gpointer owl_log_thread_func(gpointer data)
    430255{
     256  log_context = g_main_context_new();
    431257  log_loop = g_main_loop_new(log_context, FALSE);
    432258  g_main_loop_run(log_loop);
     
    434260}
    435261
    436 void owl_log_init(void) 
     262void owl_log_init(void)
    437263{
    438264  log_context = g_main_context_new();
     
    454280  }
    455281#endif
    456  
     282
     283  deferred_entry_queue = g_queue_new();
    457284}
    458285
    459286static void owl_log_quit_func(gpointer data)
    460287{
     288  /* flush the deferred logs queue, trying to write the
     289   * entries to the disk one last time.  Drop any failed
     290   * entries, and be quiet about it. */
     291  owl_log_options opts;
     292  opts.drop_failed_logs = true;
     293  opts.display_initial_log_count = false;
     294  owl_log_write_deferred_entries(&opts);
     295#if GLIB_CHECK_VERSION(2, 32, 0)
     296  g_queue_free_full(deferred_entry_queue, owl_log_entry_delete);
     297#else
     298  g_queue_foreach(deferred_entry_queue, owl_log_entry_delete_gfunc, NULL);
     299  g_queue_free(deferred_entry_queue);
     300#endif
     301
    461302  g_main_loop_quit(log_loop);
    462303}
  • message.c

    r7dcef03 r4fd3c04  
    3030void owl_message_init(owl_message *m)
    3131{
     32  /* ctime_r requires a 26-byte buffer */
     33  char timestr[26];
     34
    3235  m->id=owl_global_get_nextmsgid(&g);
    3336  owl_message_set_direction_none(m);
     
    4346  /* save the time */
    4447  m->time = time(NULL);
    45   m->timestr = g_strdup(ctime(&m->time));
    46   m->timestr[strlen(m->timestr)-1] = '\0';
     48  ctime_r(&m->time, timestr);
     49  m->timestr = g_strndup(timestr, strlen(timestr) - 1);
    4750
    4851  m->fmtext = NULL;
     
    349352CALLER_OWN char *owl_message_format_time(const owl_message *m)
    350353{
    351   return owl_util_format_time(localtime(&m->time));
     354  struct tm tm;
     355  return owl_util_format_time(localtime_r(&m->time, &tm));
    352356}
    353357
     
    365369{
    366370  owl_message_set_attribute(m, "type", "zephyr");
    367 }
    368 
    369 void owl_message_set_type_aim(owl_message *m)
    370 {
    371   owl_message_set_attribute(m, "type", "AIM");
    372371}
    373372
     
    391390{
    392391  return owl_message_is_type(m, "zephyr");
    393 }
    394 
    395 int owl_message_is_type_aim(const owl_message *m)
    396 {
    397   return owl_message_is_type(m, "aim");
    398 }
    399 
    400 /* XXX TODO: deprecate this */
    401 int owl_message_is_type_jabber(const owl_message *m)
    402 {
    403   return owl_message_is_type(m, "jabber");
    404392}
    405393
     
    599587CALLER_OWN GList *owl_message_get_cc_without_recipient(const owl_message *m)
    600588{
    601   char *cc, *shortuser, *recip;
     589  char *cc, *shortuser, *recip, *saveptr;
    602590  const char *user;
    603591  GList *out = NULL;
     
    609597  recip = short_zuser(owl_message_get_recipient(m));
    610598
    611   user = strtok(cc, " ");
     599  user = strtok_r(cc, " ", &saveptr);
    612600  while (user != NULL) {
    613601    shortuser = short_zuser(user);
     
    616604    }
    617605    g_free(shortuser);
    618     user = strtok(NULL, " ");
     606    user = strtok_r(NULL, " ", &saveptr);
    619607  }
    620608
     
    689677
    690678
    691 /* if loginout == -1 it's a logout message
    692  *                 0 it's not a login/logout message
    693  *                 1 it's a login message
    694  */
    695 void owl_message_create_aim(owl_message *m, const char *sender, const char *recipient, const char *text, int direction, int loginout)
    696 {
    697   owl_message_init(m);
    698   owl_message_set_body(m, text);
    699   owl_message_set_sender(m, sender);
    700   owl_message_set_recipient(m, recipient);
    701   owl_message_set_type_aim(m);
    702 
    703   if (direction==OWL_MESSAGE_DIRECTION_IN) {
    704     owl_message_set_direction_in(m);
    705   } else if (direction==OWL_MESSAGE_DIRECTION_OUT) {
    706     owl_message_set_direction_out(m);
    707   }
    708 
    709   /* for now all messages that aren't loginout are private */
    710   if (!loginout) {
    711     owl_message_set_isprivate(m);
    712   }
    713 
    714   if (loginout==-1) {
    715     owl_message_set_islogout(m);
    716   } else if (loginout==1) {
    717     owl_message_set_islogin(m);
    718   }
    719 }
    720 
    721679void owl_message_create_admin(owl_message *m, const char *header, const char *text)
    722680{
     
    781739  struct hostent *hent;
    782740#endif /* ZNOTICE_SOCKADDR */
    783   char *tmp, *tmp2;
     741  /* ctime_r requires a 26-byte buffer */
     742  char timestr[26], *tmp, *tmp2;
    784743  int len;
    785744
     
    799758  if (m->timestr) g_free(m->timestr);
    800759  m->time = n->z_time.tv_sec;
    801   m->timestr = g_strdup(ctime(&m->time));
    802   m->timestr[strlen(m->timestr)-1] = '\0';
     760  ctime_r(&m->time, timestr);
     761  m->timestr = g_strndup(timestr, strlen(timestr) - 1);
    803762
    804763  /* set other info */
  • owl.c

    r441fd42 r4fd3c04  
    187187      if (owl_message_is_type_zephyr(m)) {
    188188        owl_zephyr_zaway(m);
    189       } else if (owl_message_is_type_aim(m)) {
    190         if (owl_message_is_private(m)) {
    191           owl_function_send_aimawymsg(owl_message_get_sender(m), owl_global_get_zaway_msg(&g));
    192         }
    193189      }
    194190    }
     
    230226  /* let perl know about it */
    231227  owl_perlconfig_newmsg(m, NULL);
    232   /* log the message if we need to */
    233   owl_log_message(m);
    234228  /* redraw the sepbar; TODO: don't violate layering */
    235229  owl_global_sepbar_dirty(&g);
     
    506500  owl_global_set_startupargs(&g, argc_copy, argv_copy);
    507501  g_strfreev(argv_copy);
    508   owl_global_set_haveaim(&g);
    509502
    510503  owl_register_signal_handlers();
     
    566559                  owl_global_get_filter(&g, "all"),
    567560                  owl_global_get_style_by_name(&g, "default"));
    568 
    569   /* AIM init */
    570   owl_function_debugmsg("startup: doing AIM initialization");
    571   owl_aim_init();
    572561
    573562  /* execute the startup function in the configfile */
  • perl/Makefile.am

    ra870319 r4fd3c04  
    22nobase_dist_pkgdata_DATA = \
    33        lib/BarnOwl.pm \
    4         lib/BarnOwl/Complete/AIM.pm \
    54        lib/BarnOwl/Complete/Client.pm \
    65        lib/BarnOwl/Complete/Filter.pm \
     
    98        lib/BarnOwl/Completion/Context.pm \
    109        lib/BarnOwl/Completion/Util.pm \
     10        lib/BarnOwl/DeferredLogging.pm \
    1111        lib/BarnOwl/Editwin.pm \
    1212        lib/BarnOwl/Help.pm \
    1313        lib/BarnOwl/Hook.pm \
    1414        lib/BarnOwl/Hooks.pm \
     15        lib/BarnOwl/Logging.pm \
    1516        lib/BarnOwl/MainLoopCompatHook.pm \
    1617        lib/BarnOwl/Message.pm \
    17         lib/BarnOwl/Message/AIM.pm \
    1818        lib/BarnOwl/Message/Admin.pm \
    1919        lib/BarnOwl/Message/Generic.pm \
  • perl/lib/BarnOwl/Complete/Client.pm

    r4626016 r1f92f39  
    146146sub complete_set {
    147147    my $ctx = shift;
    148     return complete_flags($ctx,
    149         [qw(-q)],
    150         {
    151         },
    152          \&complete_set_args
    153         );
    154 }
    155 sub complete_set_args {
    156     my $ctx = shift;
    157     my $arg = shift;
    158     return if $arg;
    159     return complete_variable();
     148    my $is_unset = ($ctx->words->[0] eq "unset");
     149
     150    # Shift away the -q if seen.
     151    my $seen_q = 0;
     152    if ($ctx->word > 1 && $ctx->words->[1] eq "-q") {
     153        $seen_q = 1;
     154        $ctx = $ctx->shift_words(1);
     155    }
     156
     157    # First argument is the variable.
     158    if ($ctx->word == 1) {
     159        my @vars = complete_variable();
     160        if ($is_unset) {
     161            # Only complete the variables which are unsettable.
     162            @vars = grep { BarnOwl::get_variable_info($_)->{takes_on_off} } @vars;
     163        }
     164        unshift(@vars, "-q") unless $seen_q;
     165        return @vars;
     166    }
     167    # For set, second argument is the value.
     168    if (!$is_unset && $ctx->word == 2) {
     169        # Parse what we can out of validsettings.
     170        my $info;
     171        eval { $info = BarnOwl::get_variable_info($ctx->words->[1]) };
     172        return if $@;
     173        if ($info->{validsettings} eq "<path>") {
     174            return complete_file($ctx->words->[2]);
     175        } elsif ($info->{validsettings} !~ /^<.*>$/) {
     176            # Assume it's a comma-separated list of values;
     177            return split(",", $info->{validsettings});
     178        }
     179    }
     180    return;
    160181}
    161182
  • perl/lib/BarnOwl/Complete/Filter.pm

    r6dba228 r4fd3c04  
    3636    body      => undef,
    3737    hostname  => undef,
    38     type      => sub { qw(zephyr aim admin); },
     38    type      => sub { qw(zephyr admin); },
    3939    direction => sub { qw(in out none); },
    4040    login     => sub { qw(login logout none); },
  • perl/lib/BarnOwl/Message.pm

    r0adbce1 r4fd3c04  
    44package BarnOwl::Message;
    55
     6use File::Spec;
     7
    68use BarnOwl::Message::Admin;
    7 use BarnOwl::Message::AIM;
    89use BarnOwl::Message::Generic;
    910use BarnOwl::Message::Loopback;
     
    4142sub is_generic  { return (shift->{"type"} eq "generic"); }
    4243sub is_zephyr   { return (shift->{"type"} eq "zephyr"); }
    43 sub is_aim      { return (shift->{"type"} eq "AIM"); }
     44sub is_aim      { return ''; }
    4445sub is_jabber   { return (shift->{"type"} eq "jabber"); }
    4546sub is_icq      { return (shift->{"type"} eq "icq"); }
     
    115116    }
    116117    return $s;
     118}
     119
     120=head2 log MESSAGE
     121
     122Returns the text that should be written to a file to log C<MESSAGE>.
     123
     124=cut
     125
     126sub log {
     127    my ($m) = @_;
     128    return $m->log_header . "\n\n" . $m->log_body . "\n\n";
     129}
     130
     131=head2 log_header MESSAGE
     132
     133Returns the header of the message, for logging purposes.
     134If you override L<BarnOwl::Message::log>, this method is not called.
     135
     136=cut
     137
     138sub log_header {
     139    my ($m) = @_;
     140    my $sender = $m->sender;
     141    my $recipient = $m->recipient;
     142    my $timestr = $m->time;
     143    return "From: <$sender> To: <$recipient>\n"
     144         . "Time: $timestr";
     145}
     146
     147=head2 log_body MESSAGE
     148
     149Returns the body of the message, for logging purposes.
     150If you override L<BarnOwl::Message::log>, this method is not called.
     151
     152=cut
     153
     154sub log_body {
     155    my ($m) = @_;
     156    if ($m->is_loginout) {
     157        return uc($m->login)
     158            . $m->login_type
     159            . ($m->login_extra ? ' at ' . $m->login_extra : '');
     160    } else {
     161        return $m->body;
     162    }
     163}
     164
     165=head2 log_filenames MESSAGE
     166
     167Returns a list of filenames to which this message should be logged.
     168The filenames should be relative to the path returned by C<log_path>.
     169See L<BarnOwl::Logging::get_filenames> for the specification of valid
     170filenames, and for what happens if this method returns an invalid
     171filename.
     172
     173=cut
     174
     175sub log_filenames {
     176    my ($m) = @_;
     177    my $filename;
     178    if ($m->is_incoming) {
     179        $filename = $m->pretty_sender;
     180    } elsif ($m->is_outgoing) {
     181        $filename = $m->pretty_recipient;
     182    }
     183    $filename = "unknown" if !defined($filename) || $filename eq '';
     184    if (BarnOwl::getvar('log-to-subdirectories') eq 'on') {
     185        return ($filename);
     186    } else {
     187        return ($m->log_subfolder . ':' . $filename);
     188    }
     189}
     190
     191=head2 log_to_all_file MESSAGE
     192
     193There is an C<all> file.  This method determines if C<MESSAGE>
     194should get logged to it, in addition to any files returned by
     195C<log_filenames>.
     196
     197It defaults to returning true if and only if C<MESSAGE> is outgoing.
     198
     199=cut
     200
     201sub log_to_all_file {
     202    my ($m) = @_;
     203    return $m->is_outgoing;
     204}
     205
     206=head2 log_path MESSAGE
     207
     208Returns the folder in which all messages of this class get logged.
     209
     210Defaults to C<log_base_path/log_subfolder> if C<log-to-subdirectories>
     211is enabled, or to the C<logpath> BarnOwl variable if it is not.
     212
     213Most protocols should override C<log_subfolder> rather than
     214C<log_path>, in order to properly take into account the value of
     215C<log-to-subdirectories>.
     216
     217=cut
     218
     219sub log_path {
     220    my ($m) = @_;
     221    if (BarnOwl::getvar('log-to-subdirectories') eq 'on') {
     222        return File::Spec->catfile($m->log_base_path, $m->log_subfolder);
     223    } else {
     224        return BarnOwl::getvar('logpath');
     225    }
     226}
     227
     228=head2 log_base_path MESSAGE
     229
     230Returns the base path for logging.  See C<log_path> for more information.
     231
     232Defaults to the BarnOwl variable C<logbasepath>.
     233
     234=cut
     235
     236sub log_base_path {
     237    return BarnOwl::getvar('logbasepath');
     238}
     239
     240=head2 log_subfolder MESSAGE
     241
     242Returns the subfolder of C<log_base_path> to log messages in.
     243
     244Defaults to C<lc($m->type)>.
     245
     246=cut
     247
     248sub log_subfolder {
     249    return lc(shift->type);
     250}
     251
     252=head2 log_outgoing_error MESSAGE
     253
     254Returns the string that should be logged if there is an error sending
     255an outgoing message.
     256
     257=cut
     258
     259sub log_outgoing_error {
     260    my ($m) = @_;
     261    my $recipient = $m->pretty_recipient;
     262    my $body = $m->body;
     263    chomp $body;
     264    return "ERROR (BarnOwl): $recipient\n$body\n\n";
     265}
     266
     267=head2 should_log MESSAGE
     268
     269Returns true if we should log C<MESSAGE>.  This does not override
     270user settings; if the BarnOwl variable C<loggingdirection> is in,
     271and C<MESSAGE> is outgoing and does not match the C<logfilter>, it
     272will not get logged regardless of what this method returns.
     273
     274Note that this method I<does> override the BarnOwl C<logging>
     275variable; if a derived class overrides this method and does not
     276provide an alternative BarnOwl variable (such as C<classlogging>),
     277the overriding method should check the BarnOwl C<logging> variable.
     278
     279Defaults to returning the value of the BarnOwl variable C<logging>.
     280
     281=cut
     282
     283sub should_log {
     284    return BarnOwl::getvar('logging') eq 'on';
    117285}
    118286
  • perl/lib/BarnOwl/Message/Loopback.pm

    ree183be r8cec8f7  
    1414sub replysendercmd {return 'loopwrite';}
    1515
     16sub log_subfolder { return ''; }
     17sub log_filenames { return ('loopback'); }
    1618
    17191;
  • perl/lib/BarnOwl/Message/Zephyr.pm

    r0adbce1 r8f91a70  
    2121    my ($user, $realm) = split(/@/,$principal);
    2222    return $realm;
     23}
     24
     25sub casefold_principal {
     26    my $principal = shift;
     27    # split the principal right after the final @, without eating any
     28    # characters; this way, we always get at least '@' in $user
     29    my ($user, $realm) = split(/(?<=@)(?=[^@]+$)/, $principal);
     30    $user = '' if !defined $user;
     31    $user = lc($user);
     32    $user = $user . uc($realm) if defined $realm;
     33    return $user;
    2334}
    2435
     
    132143    return $1 if $self->body =~ /^\s*cc:\s+([^\n]+)/i;
    133144    return undef;
     145}
     146
     147# Note: This is the cc-line without the recipient; it does not include
     148# the sender.
     149sub zephyr_cc_without_recipient {
     150    my $self = shift;
     151    my $recipient = lc(strip_realm($self->recipient));
     152    my $cc = $self->zephyr_cc;
     153    return grep { lc(strip_realm($_)) ne $recipient } split(/\s+/, $cc) if defined $cc;
     154    return ();
    134155}
    135156
     
    223244}
    224245
     246# Logging
     247sub log_header {
     248    my ($m) = @_;
     249    my $class = $m->class;
     250    my $instance = $m->instance;
     251    my $opcode = $m->opcode;
     252    my $timestr = $m->time;
     253    my $host = $m->host;
     254    my $sender = $m->pretty_sender;
     255    my $zsig = $m->zsig;
     256    my $rtn = "Class: $class Instance: $instance";
     257    $rtn .= " Opcode: $opcode" unless !defined $opcode || $opcode eq '';
     258    $rtn .= "\nTime: $timestr Host: $host"
     259          . "\nFrom: $zsig <$sender>";
     260    return $rtn;
     261}
     262
     263sub log_filenames {
     264    my ($m) = @_;
     265    my @filenames = ();
     266    if ($m->is_personal) {
     267        # If this has CC's, add all but the "recipient" which we'll add below
     268        @filenames = $m->zephyr_cc_without_recipient;
     269    }
     270    if ($m->is_incoming) {
     271        if ($m->is_personal) {
     272            push @filenames, $m->sender;
     273        } else {
     274            my $realm = '';
     275            $realm .= '@' . $m->realm if $m->realm ne BarnOwl::zephyr_getrealm();
     276            return (BarnOwl::compat_casefold($m->class) . uc($realm));
     277        }
     278    } else {
     279        push @filenames, $m->recipient;
     280    }
     281    return map { casefold_principal(BarnOwl::zephyr_smartstrip_user(strip_realm($_))) } @filenames;
     282}
     283
     284sub log_to_class_file {
     285    my ($m) = @_;
     286    return !$m->is_personal;
     287}
     288
     289sub log_path {
     290    my ($m) = @_;
     291    if ($m->log_to_class_file) {
     292        return BarnOwl::getvar('classlogpath');
     293    } else {
     294        return BarnOwl::getvar('logpath');
     295    }
     296}
     297
     298sub should_log {
     299    my ($m) = @_;
     300    if ($m->log_to_class_file) {
     301        return BarnOwl::getvar('classlogging') eq 'on';
     302    } else {
     303        return BarnOwl::getvar('logging') eq 'on';
     304    }
     305}
    225306
    2263071;
  • perl/modules/IRC/lib/BarnOwl/Message/IRC.pm

    r60b49a7 r3f0c209  
    9292}
    9393
     94# logging
     95sub log_filenames {
     96    my ($m) = @_;
     97    die "IRC should not be handling non-IRC messages" if lc($m->type) ne "irc";
     98    BarnOwl::error("IRC message without a network") if !defined($m->network) || $m->network eq '';
     99    my $filename = lc($m->network);
     100    # Note: Channel names generally start with '#', which
     101    # disambiguates channels from individuals; for example, personals
     102    # will look like, e.g., "~/zlog/irc/freenode:john-doe", whereas
     103    # channels will look like, e.g., "~/zlog/irc/freenode:#barnowl"
     104    if ($m->is_personal) {
     105        if ($m->is_incoming) {
     106            $filename .= ":" . $m->sender;
     107        } elsif ($m->is_outgoing) {
     108            $filename .= ":" . $m->recipient;
     109        }
     110    } else {
     111        $filename .= ":" . $m->channel;
     112    }
     113    return ($filename);
     114}
     115
     116sub log {
     117    my ($m) = @_;
     118    my $sender = $m->sender;
     119    my $timestr = $m->time;
     120    my $body = $m->body;
     121    if ($m->is_loginout) {
     122        return BarnOwl::Message::log($m);
     123    } else {
     124        return "[$timestr] <$sender> $body\n";
     125    }
     126}
     127
    941281;
  • perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm

    ra27acf7 rd2ba33c  
    172172}
    173173
     174sub log_filenames {
     175    return map { BarnOwl::compat_casefold($_) } BarnOwl::Message::log_filenames(@_);
     176}
     177
    174178=head1 SEE ALSO
    175179
  • perl/modules/Makefile.am

    re4b8f93 r268c7e8  
    1 MODULES = Jabber IRC WordWrap Twitter Facebook
     1MODULES = Jabber IRC WordWrap Twitter Facebook Kerberos
    22
    33EXTRA_DIST = $(MODULES:=/Makefile.PL) $(MODULES:=/lib)
  • perlconfig.c

    r7dcef03 r09530e6  
    211211      g_free(m->timestr);
    212212      m->timestr = g_strdup(val);
     213      // FIXME: Daylight saving time will be guessed wrongly one hour per year!
     214      tm.tm_isdst = -1;
    213215      strptime(val, "%a %b %d %T %Y", &tm);
    214216      m->time = mktime(&tm);
  • scripts/do-release

    rb8a3e00 rbc308eb  
    1 #!/bin/sh -e
     1#!/bin/bash
     2set -eu
    23
    34die() {
     
    5556fi
    5657
     58[ -e Makefile.in ] || autoreconf -fvi
     59[ -e config.status ] || ./configure
     60make -j4 distcheck VERSION="$VERS"
     61
     62echo 'Checking distributed files against Git:'
     63if comm -3 <(tar -tzf "$TAG.tar.gz" | grep -v '/$' | sed "s%^$TAG/%%" | sort) \
     64    <(git ls-files | sort) | grep -vxf scripts/dist-ignore; then
     65    echo
     66    echo 'Error: Please fix Makefile.am and/or scripts/dist-ignore.'
     67    exit 1
     68fi
     69echo 'ok'
     70
     71mv "$TAG.tar.gz" "$TGZ.tgz"
     72
    5773if ! [ "$no_tag" ]; then
    5874    if git cat-file -t "$TAG" > /dev/null 2>&1; then
     
    6581fi
    6682
    67 exittrap() { :; }
    68 for sig in 1 2 13 15; do trap "exit $(($sig + 128))" $sig; done
    69 trap 'exittrap' EXIT
    70 
    71 TMPDIR=$(mktemp -d /tmp/barnowl.XXXXXX)
    72 
    73 exittrap() { rm -rf "$TMPDIR"; }
    74 
    75 git archive --format=tar --prefix="$TGZ/" "$TAG" | tar -x -C "$TMPDIR"
    76 
    77 CODIR=$(pwd)
    78 cd "$TMPDIR/$TGZ"
    79 [ "$git" ] && perl -i -pe 's{^(AC_INIT\(\[[^\]]+\],\s*)\[([^\]]+)\]}{${1}['$VERS']}' configure.ac
    80 autoreconf -fvi
    81 rm -r autom4te.cache/
    82 cd "$TMPDIR"
    83 tar czvf "$TGZ.tgz" "$TGZ"
    84 cd "$CODIR"
    85 
    86 mv "$TMPDIR/$TGZ.tgz" .
    87 rm -rf "$TMPDIR"
    88 
    89 exittrap() { :; }
    90 
    91 echo "Created release tarball for BarnOwl $VERS in $(pwd)"
     83echo "Created release tarball for BarnOwl $VERS at $(pwd)/$TGZ.tgz"
    9284echo "Remember to bump OWL_VERSION_STRING for future development."
    9385
  • t/completion.t

    re59d775 r4fd3c04  
    66
    77use File::Basename;
    8 BEGIN {require (dirname($0) . "/mock.pl");};
     8use File::Spec;
     9BEGIN {require File::Spec->rel2abs("mock.pl", dirname($0));};
    910
    1011use BarnOwl::Complete::Filter qw(complete_filter_expr);
     
    292293
    293294test_complete('type ', '',
    294               [qw[admin aim zephyr]],
     295              [qw[admin zephyr]],
    295296              \&complete_filter_expr);
    296297
  • util.c

    rcba6b9c rd2ba33c  
    643643}
    644644
     645CALLER_OWN char *owl_util_compat_casefold(const char *str)
     646{
     647  /*
     648   * Quoting Anders Kaseorg at https://github.com/barnowl/barnowl/pull/54#issuecomment-31452543:
     649   *
     650   * The Unicode specification calls this compatibility caseless matching, and
     651   * the correct transformation actually has five calls:
     652   * NFKC(toCasefold(NFKD(toCasefold(NFD(string))))) Zephyr’s current
     653   * implementation incorrectly omits the innermost NFD, but that difference
     654   * only matters for characters including U+0345 ◌ͅ COMBINING GREEK
     655   * YPOGEGRAMMENI. I think we should just write the correct version and get
     656   * Zephyr fixed.
     657   *
     658   * Neither of these operations should be called toNFKC_Casefold, because that
     659   * has slightly different behavior regarding Default_Ignorable_Code_Point. I
     660   * propose compat_casefold. And I guess if Jabber wants it too, we should
     661   * move it to util.c.
     662   */
     663  char *tmp0 = g_utf8_normalize(str, -1, G_NORMALIZE_NFD);
     664  char *tmp1 = g_utf8_casefold(tmp0, -1);
     665  char *tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_NFKD);
     666  char *tmp3 = g_utf8_casefold(tmp2, -1);
     667  char *out = g_utf8_normalize(tmp3, -1, G_NORMALIZE_NFKC);
     668  g_free(tmp0);
     669  g_free(tmp1);
     670  g_free(tmp2);
     671  g_free(tmp3);
     672
     673  return out;
     674}
     675
    645676/* This is based on _extract() and _isCJ() from perl's Text::WrapI18N */
    646677int owl_util_can_break_after(gunichar c)
  • variable.c

    r94b9ee0 r4fd3c04  
    136136               "load logins from .anyone on startup", "" );
    137137
    138   OWLVAR_BOOL( "logging" /* %OwlVarStub */, 0,
    139                "turn personal logging on or off",
    140                "If this is set to on, personal messages are\n"
    141                "logged in the directory specified\n"
    142                "by the 'logpath' variable.  The filename in that\n"
    143                "directory is derived from the sender of the message.\n" );
    144 
    145   OWLVAR_BOOL( "classlogging" /* %OwlVarStub */, 0,
    146                "turn class logging on or off",
    147                "If this is set to on, class messages are\n"
    148                "logged in the directory specified\n"
    149                "by the 'classlogpath' variable.\n"
    150                "The filename in that directory is derived from\n"
    151                "the name of the class to which the message was sent.\n" );
    152 
    153   OWLVAR_ENUM( "loggingdirection" /* %OwlVarStub */, OWL_LOGGING_DIRECTION_BOTH,
    154                "specifies which kind of messages should be logged",
    155                "Can be one of 'both', 'in', or 'out'.  If 'in' is\n"
    156                "selected, only incoming messages are logged, if 'out'\n"
    157                "is selected only outgoing messages are logged.  If 'both'\n"
    158                "is selected both incoming and outgoing messages are\n"
    159                "logged.",
    160                "both,in,out");
    161 
    162138  OWLVAR_BOOL_FULL( "colorztext" /* %OwlVarStub */, 1,
    163139                    "allow @color() in zephyrs to change color",
    164                     NULL, NULL, owl_variable_colorztext_set, NULL);
     140                    "", NULL, owl_variable_colorztext_set, NULL);
    165141
    166142  OWLVAR_BOOL( "fancylines" /* %OwlVarStub */, 1,
     
    185161               "Enable printing of login notifications",
    186162               "When this is enabled, BarnOwl will print login and logout notifications\n"
    187                "for AIM, zephyr, or other protocols.  If disabled BarnOwl will not print\n"
    188                "login or logout notifications.\n");
    189 
    190   OWLVAR_STRING( "logfilter" /* %OwlVarStub */, "",
    191                  "name of a filter controlling which messages to log",
    192 
    193                  "If non empty, any messages matching the given filter will be logged.\n"
    194                  "This is a completely separate mechanism from the other logging\n"
    195                  "variables like logging, classlogging, loglogins, loggingdirection,\n"
    196                  "etc.  If you want this variable to control all logging, make sure\n"
    197                  "all other logging variables are in their default state.\n");
    198 
    199   OWLVAR_BOOL( "loglogins" /* %OwlVarStub */, 0,
    200                "Enable logging of login notifications",
    201                "When this is enabled, BarnOwl will log login and logout notifications\n"
    202                "for AIM, zephyr, or other protocols.  If disabled BarnOwl will not print\n"
     163               "for zephyr or other protocols.  If disabled BarnOwl will not print\n"
    203164               "login or logout notifications.\n");
    204165
     
    214175                    "off,middle,on",
    215176                    NULL, owl_variable_disable_ctrl_d_set, NULL);
    216 
    217   OWLVAR_PATH( "logpath" /* %OwlVarStub */, "~/zlog/people",
    218                "path for logging personal zephyrs",
    219                "Specifies a directory which must exist.\n"
    220                "Files will be created in the directory for each sender.\n");
    221 
    222   OWLVAR_PATH( "classlogpath" /* %OwlVarStub:classlogpath */, "~/zlog/class",
    223                "path for logging class zephyrs",
    224                "Specifies a directory which must exist.\n"
    225                "Files will be created in the directory for each class.\n");
    226177
    227178  OWLVAR_PATH( "debug_file" /* %OwlVarStub */, OWL_DEBUG_FILE,
     
    282233                 "default zaway message", "" );
    283234
    284   OWLVAR_BOOL_FULL( "aaway" /* %OwlVarStub */, 0,
    285                     "Set AIM away status",
    286                     "",
    287                     NULL, owl_variable_aaway_set, NULL);
    288 
    289   OWLVAR_STRING( "aaway_msg" /* %OwlVarStub */,
    290                  OWL_DEFAULT_AAWAYMSG,
    291                  "AIM away msg for responding when away", "" );
    292 
    293   OWLVAR_STRING( "aaway_msg_default" /* %OwlVarStub */,
    294                  OWL_DEFAULT_AAWAYMSG,
    295                  "default AIM away message", "" );
    296 
    297235  OWLVAR_STRING( "view_home" /* %OwlVarStub */, "all",
    298236                 "home view to switch to after 'X' and 'V'",
     
    337275                 "Zephyr messages be no wider than 70 columns.\n");
    338276
    339   OWLVAR_INT( "aim_ignorelogin_timer" /* %OwlVarStub */, 15,
    340               "number of seconds after AIM login to ignore login messages",
    341               "This specifies the number of seconds to wait after an\n"
    342               "AIM login before allowing the receipt of AIM login notifications.\n"
    343               "By default this is set to 15.  If you would like to view login\n"
    344               "notifications of buddies as soon as you login, set it to 0 instead.");
    345 
    346              
    347277  OWLVAR_INT_FULL( "typewinsize" /* %OwlVarStub:typwin_lines */,
    348278                   OWL_TYPWIN_SIZE,
     
    510440}
    511441
    512 /* When 'aaway' is changed, need to notify the AIM server */
    513 int owl_variable_aaway_set(owl_variable *v, bool newval)
    514 {
    515   if (newval) {
    516     owl_aim_set_awaymsg(owl_global_get_aaway_msg(&g));
    517   } else {
    518     owl_aim_set_awaymsg("");
    519   }
    520   return owl_variable_bool_set_default(v, newval);
    521 }
    522 
    523442int owl_variable_colorztext_set(owl_variable *v, bool newval)
    524443{
     
    814733}
    815734
     735bool owl_variable_takes_on_off(const owl_variable *v) {
     736  return v->takes_on_off;
     737}
     738
    816739int owl_variable_get_type(const owl_variable *v)
    817740{
  • zcrypt.c

    rca1fb26a r9a0d25d  
    2121#include <config.h>
    2222
    23 #ifdef HAVE_KERBEROS_IV
    24 #include <kerberosIV/des.h>
    25 #else
    2623#include <openssl/des.h>
    27 #endif
    2824
    2925#include "filterproc.h"
     
    9995};
    10096
    101 static void owl_zcrypt_string_to_schedule(char *keystring, des_key_schedule *schedule) {
    102 #ifdef HAVE_KERBEROS_IV
    103   des_cblock key;
    104 #else
    105   des_cblock _key, *key = &_key;
    106 #endif
    107 
    108   des_string_to_key(keystring, key);
    109   des_key_sched(key, *schedule);
     97static void owl_zcrypt_string_to_schedule(char *keystring, DES_key_schedule *schedule) {
     98  DES_cblock key;
     99
     100  DES_string_to_key(keystring, &key);
     101  DES_key_sched(&key, schedule);
    110102}
    111103
     
    728720int do_encrypt_des(const char *keyfile, const char *in, int length, FILE *outfile)
    729721{
    730   des_key_schedule schedule;
     722  DES_key_schedule schedule;
    731723  unsigned char input[8], output[8];
    732724  const char *inptr;
     
    774766
    775767    /* Encrypt and output the block */
    776     des_ecb_encrypt(&input, &output, schedule, TRUE);
     768    DES_ecb_encrypt(&input, &output, &schedule, TRUE);
    777769    block_to_ascii(output, outfile);
    778770
     
    790782  char *out;
    791783  int err, status;
     784  int tried_gpg1 = FALSE;
    792785  const char *argv[] = {
    793     "gpg",
     786    "gpg1",
    794787    "--symmetric",
    795788    "--no-options",
     
    805798    NULL
    806799  };
    807   err = call_filter(argv, in, &out, &status);
     800  while ((err = call_filter(argv, in, &out, &status)) && !out && !tried_gpg1) {
     801    tried_gpg1 = TRUE;
     802    argv[0] = "gpg";
     803  }
    808804  if(err || status) {
    809805    g_free(out);
     
    874870  char *in, *out;
    875871  int length;
     872  int tried_gpg1 = FALSE;
    876873  const char *argv[] = {
    877     "gpg",
     874    "gpg1",
    878875    "--decrypt",
    879876    "--no-options",
     
    892889  if(!in) return FALSE;
    893890
    894   err = call_filter(argv, in, &out, &status);
     891  while ((err = call_filter(argv, in, &out, &status)) && !out && !tried_gpg1) {
     892    tried_gpg1 = TRUE;
     893    argv[0] = "gpg";
     894  }
    895895  free(in);
    896896  if(err || status) {
     
    905905
    906906int do_decrypt_des(const char *keyfile) {
    907   des_key_schedule schedule;
     907  DES_key_schedule schedule;
    908908  unsigned char input[8], output[8];
    909909  char tmp[9];
     
    915915    have a NULL-terminated string we can call printf/strlen on.
    916916
    917     We don't pass 'tmp' to des_ecb_encrypt directly, because it's
     917    We don't pass 'tmp' to DES_ecb_encrypt directly, because it's
    918918    prototyped as taking 'unsigned char[8]', and this avoids a stupid
    919919    cast.
     
    933933  while (read_ascii_block(input))
    934934  {
    935     des_ecb_encrypt(&input, &output, schedule, FALSE);
     935    DES_ecb_encrypt(&input, &output, &schedule, FALSE);
    936936    memcpy(tmp, output, 8);
    937937    printf("%s", tmp);
  • zephyr.c

    rff58239 ree6b30f  
    284284  FILE *file;
    285285  int fopen_errno;
    286   char *tmp, *start;
     286  char *tmp, *start, *saveptr;
    287287  char *buffer = NULL;
    288288  char *subsfile;
     
    319319   
    320320    /* add it to the list of subs */
    321     if ((tmp = strtok(start, ",\n\r")) == NULL)
     321    if ((tmp = strtok_r(start, ",\n\r", &saveptr)) == NULL)
    322322      continue;
    323323    subs[count].zsub_class = g_strdup(tmp);
    324     if ((tmp=strtok(NULL, ",\n\r")) == NULL)
     324    if ((tmp = strtok_r(NULL, ",\n\r", &saveptr)) == NULL)
    325325      continue;
    326326    subs[count].zsub_classinst = g_strdup(tmp);
    327     if ((tmp = strtok(NULL, " \t\n\r")) == NULL)
     327    if ((tmp = strtok_r(NULL, " \t\n\r", &saveptr)) == NULL)
    328328      continue;
    329329    subs[count].zsub_recipient = g_strdup(tmp);
  • zwrite.c

    r7dcef03 r1958790  
    270270  rv = owl_zwrite_create_from_line(&z, cmd);
    271271  if (rv != 0) return rv;
    272   if (!owl_zwrite_is_message_set(&z)) {
    273     owl_zwrite_set_message(&z, msg);
    274   }
    275   owl_zwrite_populate_zsig(&z);
    276   owl_zwrite_send_message(&z);
     272  owl_function_zwrite(&z, msg);
    277273  owl_zwrite_cleanup(&z);
    278274  return(0);
Note: See TracChangeset for help on using the changeset viewer.