Changeset c2a8e22


Ignore:
Timestamp:
Feb 4, 2019, 10:30:04 AM (6 years ago)
Author:
GitHub <noreply@github.com>
Parents:
9a0d25d (diff), 10e2295 (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:
Edward Z. Yang <ezyang@mit.edu> (02/04/19 10:30:04)
git-committer:
GitHub <noreply@github.com> (02/04/19 10:30:04)
Message:
Merge 10e22953bdafd75b19a929d91dbd11afad9af15c into 9a0d25d1513e92f2b0c99d89ab5fc5ae2c061151
Files:
7 added
44 deleted
43 edited

Legend:

Unmodified
Added
Removed
  • README

    r1c22155 rea23e6d  
    5555The Twitter module requires:
    5656
    57 HTML::Entities
     57HTML::Entities (provided by HTML::Parser)
    5858Net::Twitter::Lite
    5959
  • perl/modules/Twitter/lib/BarnOwl/Message/Twitter.pm

    r8106870 r10e2295  
    2222    $self->service =~ m#^\s*(.*?://.*?)/.*$#;
    2323    my $service = $1 || $self->service;
    24     my $long = $service . '/' . $self->sender;
     24    my $long = $service . '/' . $self->sender . '/status/' . $self->{status_id};
    2525    if ($self->retweeted_by) {
    2626        $long = "(retweeted by " . $self->retweeted_by . ") $long";
     
    3333    if($self->is_private) {
    3434        return $self->replysendercmd;
    35     } elsif(exists($self->{status_id})) {
    36         return BarnOwl::quote('twitter-atreply', $self->sender, $self->{status_id}, $self->account);
     35    }
     36    # Roughly, this is how Twitter's @-reply calculation works
     37    # (based on a few experiments)
     38    #
     39    #   1. The person who wrote the tweet you are replying to is added.
     40    #      This is the only time when your own name can show up in an
     41    #      at-reply string.
     42    #   2. Next, Twitter goes through the Tweet front to back, adding
     43    #      mentioned usernames that have not already been added to the
     44    #      string.
     45    #
     46    # In degenerate cases, the at-reply string might be longer than
     47    # the max Tweet size; Twitter doesn't care.
     48
     49    # XXX A horrifying violation of encapsulation
     50    # NB: names array includes @-signs.
     51    my $account = BarnOwl::Module::Twitter::find_account_default($self->{account});
     52    my @inside_names = grep($_ ne ("@" . $account->{cfg}->{user}),
     53                            $self->{body} =~ /(?:^|\s)(@\w+)/g );
     54    my @dup_names = ( ( "@" . $self->sender ), @inside_names );
     55
     56    # XXX Really should use List::MoreUtils qw(uniq).  This code snippet
     57    # lifted from `perldoc -q duplicate`.
     58    my %seen = ();
     59    my @names = grep { ! $seen{ $_ }++ } @dup_names;
     60    my $prefill = join(' ', @names) . ' '; # NB need trailing space
     61
     62    if(exists($self->{status_id})) {
     63        return BarnOwl::quote('twitter-prefill', $prefill, $self->{status_id}, $self->account);
    3764    } else {
    38         return BarnOwl::quote('twitter-atreply', $self->sender, $self->account);
     65        # Give a dummy status ID
     66        return BarnOwl::quote('twitter-prefill', $prefill, '', $self->account);
    3967    }
    4068}
  • perl/modules/Twitter/lib/BarnOwl/Module/Twitter.pm

    r140429f r8de7c84  
    243243BarnOwl::new_command(twitter => \&cmd_twitter, {
    244244    summary     => 'Update Twitter from BarnOwl',
    245     usage       => 'twitter [ACCOUNT] [MESSAGE]',
     245    usage       => 'twitter [ACCOUNT [MESSAGE]]',
    246246    description => 'Update Twitter on ACCOUNT. If MESSAGE is provided, use it as your status.'
    247247    . "\nIf no ACCOUNT is provided, update all services which have publishing enabled."
     
    259259    {
    260260    summary     => 'Send a Twitter @ message',
    261     usage       => 'twitter-atreply USER [ACCOUNT]',
     261    usage       => 'twitter-atreply USER [ID [ACCOUNT]]',
    262262    description => 'Send a Twitter @reply Message to USER on ACCOUNT (defaults to default_sender,'
     263    . "\nor first service if no default is provided)"
     264    }
     265);
     266
     267BarnOwl::new_command( 'twitter-prefill' => sub { cmd_twitter_prefill(@_); },
     268    {
     269    summary     => 'Send a Twitter message with prefilled text',
     270    usage       => 'twitter-prefill PREFILL [ID [ACCOUNT]]',
     271    description => 'Send a Twitter message with initial text PREFILL on ACCOUNT (defaults to default_sender,'
    263272    . "\nor first service if no default is provided)"
    264273    }
     
    356365                            sub { $account->twitter_atreply($user, $id, shift) });
    357366    BarnOwl::Editwin::insert_text("\@$user ");
     367}
     368
     369sub cmd_twitter_prefill {
     370    my $cmd  = shift;
     371    # prefill is responsible for spacing
     372    my $prefill = shift || die("Usage: $cmd PREFILL [In-Reply-To ID]\n");
     373    my $id   = shift;
     374    my $account = find_account_default(shift);
     375
     376    my $msg = "What's happening?";
     377    if ($id) {
     378        # So, this isn't quite semantically correct, but it's close
     379        # enough, and under the planned use-case, it will look identical.
     380        $msg = "Reply to " . $prefill;
     381    }
     382    if ($account->nickname) {
     383        # XXX formatting slightly suboptimal on What's happening message;
     384        # and the behavior does not match up with 'twitter' anyhoo,
     385        # which doesn't dispatch through account_find_default
     386        $msg .= " on " . $account->nickname;
     387    }
     388    BarnOwl::start_edit_win($msg,
     389                            sub { $account->twitter_atreply(undef, $id, shift) });
     390    BarnOwl::Editwin::insert_text($prefill);
    358391}
    359392
  • .travis.yml

    r48c09d4 rbecd617  
    11language: perl
     2sudo: false
    23compiler:
    34  - clang
     
    910  - "5.16"
    1011  - "5.18"
    11   - "5.19"
    12 install:
    13   - sudo apt-get update -q
    14 # we actually want debhelper >= 7, libperl-dev >= 5.10.1-8, libzephyr-dev >= 3.0~beta
    15   - sudo apt-get install -q autoconf autotools-dev debhelper dh-autoreconf libglib2.0-dev libkrb5-dev libncurses5-dev libncursesw5-dev libssl-dev libzephyr-dev pkg-config zip
     12  - "5.20"
     13addons:
     14  apt:
     15    # we actually want debhelper >= 7, libperl-dev >= 5.10.1-8, libzephyr-dev >= 3.0~beta
     16    packages:
     17    - autoconf
     18    - autotools-dev
     19    - debhelper
     20    - dh-autoreconf
     21    - libglib2.0-dev
     22    - libkrb5-dev
     23    - libncurses5-dev
     24    - libncursesw5-dev
     25    - libssl-dev
     26    - libzephyr-dev
     27    - pkg-config
     28    - zip
    1629# perl things
    1730# In lp:~barnowl/barnowl/packaging, we use apt-get.  Here, we use cpanm.
    1831#  - sudo apt-get install libanyevent-perl libclass-accessor-perl libextutils-depends-perl libglib-perl libmodule-install-perl libnet-twitter-lite-perl libpar-perl libperl-dev
    19   - cpanm AnyEvent Class::Accessor ExtUtils::Depends Glib Module::Install Net::Twitter::Lite PAR
    20 script: "./autogen.sh && ./configure && make distcheck"
     32# It's taken care of by the default install script
     33script: ./autogen.sh && ./configure && make distcheck
  • 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
  • Makefile.am

    rca1fb26a r4fd3c04  
    22
    33GIT_DESCRIPTION := $(if $(wildcard $(srcdir)/.git),$(shell cd $(srcdir) && git describe --match='barnowl-*' HEAD 2>/dev/null))
    4 VERSION = $(if $(GIT_DESCRIPTION),$(GIT_DESCRIPTION:barnowl-%=%),@VERSION@)
    5 -include BUILD_VERSION.mk
     4VERSION = $(if $(GIT_DESCRIPTION),$(GIT_DESCRIPTION:barnowl-%=%),$(DIST_VERSION))
     5DIST_VERSION = @VERSION@
     6-include $(srcdir)/DIST_VERSION.mk BUILD_VERSION.mk
    67
    78FORCE:
    89BUILD_VERSION.mk: $(if $(filter-out $(BUILD_VERSION),$(VERSION)),FORCE)
    910        echo 'BUILD_VERSION = $(VERSION)' > $@
     11dist-hook:: $(if $(filter-out @VERSION@,$(VERSION)),dist-hook-version)
     12dist-hook-version:
     13        echo 'DIST_VERSION = $(VERSION)' > $(distdir)/DIST_VERSION.mk
    1014
    1115bin_PROGRAMS = bin/barnowl
     
    1418endif
    1519
    16 zcrypt_SOURCES = zcrypt.c filterproc.c version.c
     20zcrypt_SOURCES = zcrypt.c filterproc.c
     21nodist_zcrypt_SOURCES = version.c
    1722
    1823check_PROGRAMS = bin/tester
     
    3843dist_doc_DATA = doc/intro.txt doc/advanced.txt
    3944
    40 bin_barnowl_LDADD = compat/libcompat.a libfaim/libfaim.a
     45bin_barnowl_LDADD = compat/libcompat.a
    4146
    4247bin_tester_SOURCES = $(BASE_SRCS) \
     
    4550nodist_bin_tester_SOURCES = $(GEN_C) $(GEN_H)
    4651
    47 bin_tester_LDADD = compat/libcompat.a libfaim/libfaim.a
     52bin_tester_LDADD = compat/libcompat.a
    4853
    4954TESTS=runtests.sh
    5055
    5156AM_CPPFLAGS = \
    52            -I$(top_srcdir)/libfaim/ \
    5357           -DDATADIR='"$(pkgdatadir)"' \
    5458           -DBINDIR='"$(bindir)"'
     
    6064     regex.c history.c view.c dict.c variable.c filterelement.c pair.c \
    6165     keypress.c keymap.c keybinding.c cmd.c context.c \
    62      aim.c buddy.c buddylist.c style.c errqueue.c \
     66     style.c errqueue.c \
    6367     zbuddylist.c popexec.c select.c wcwidth.c \
    6468     mainpanel.c msgwin.c sepbar.c editcontext.c signal.c closures.c
     
    104108
    105109CLEANFILES = $(BUILT_SOURCES) $(GEN_C) $(noinst_SCRIPTS) $(check_SCRIPTS) BUILD_VERSION.mk
     110MAINTAINERCLEANFILES = DIST_VERSION.mk
    106111EXTRA_DIST = \
    107112    autogen.sh \
     
    116121    scripts \
    117122    stubgen.pl \
    118     typemap
     123    typemap \
     124    cpanfile
    119125
    120 SUBDIRS = compat libfaim perl
     126SUBDIRS = compat perl
  • codelist.pl

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

    rca1fb26a 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"
     
    548536              "optional color arguments are used they specifies the colors that\n"
    549537              "messages matching this filter should be displayed in.\n\n"
    550               "SEE ALSO: view, viewclass, viewuser\n"),
     538              "SEE ALSO: smartfilter, smartnarrow, view, viewclass, viewuser\n"),
    551539
    552540  OWLCMD_ARGS("colorview", owl_command_colorview, OWL_CTX_INTERACTIVE,
     
    585573              "filter expression that will be dynamically created by BarnOwl and then\n"
    586574              "applied as the view's filter\n"
    587               "SEE ALSO: filter, viewclass, viewuser\n"),
     575              "SEE ALSO: filter, smartfilter, smartnarrow, viewclass, viewuser\n"),
    588576
    589577  OWLCMD_ARGS("smartnarrow", owl_command_smartnarrow, OWL_CTX_INTERACTIVE,
     
    599587              "    then narrow to the class and instance.\n"
    600588              "If '-r' or '--related' is specified, behave as though the\n"
    601               "    'narrow-related' variable was inverted."),
     589              "    'narrow-related' variable was inverted.\n\n"
     590              "SEE ALSO: filter, smartfilter, view, viewclass, viewuser\n"),
    602591
    603592  OWLCMD_ARGS("smartfilter", owl_command_smartfilter, OWL_CTX_INTERACTIVE,
     
    610599              "If the curmsg is a class message, the filter is that class.\n"
    611600              "If the curmsg is a class message and '-i' is specified\n"
    612               "    the filter is to that class and instance.\n"),
     601              "    the filter is to that class and instance.\n\n"
     602              "SEE ALSO: filter, smartnarrow, view, viewclass, viewuser\n"),
    613603
    614604  OWLCMD_ARGS("viewclass", owl_command_viewclass, OWL_CTX_INTERACTIVE,
     
    618608              "matching the specified class and switch the current view\n"
    619609              "to it.\n\n"
    620               "SEE ALSO: filter, view, viewuser\n"),
     610              "SEE ALSO: filter, smartfilter, smartnarrow, view, viewuser\n"),
    621611  OWLCMD_ALIAS("vc", "viewclass"),
    622612
     
    627617              "matching the specified user and switch the current\n"
    628618              "view to it.\n\n"
    629               "SEE ALSO: filter, view, viewclass\n"),
     619              "SEE ALSO: filter, smartfilter, smartnarrow, view, viewclass\n"),
    630620  OWLCMD_ALIAS("vu", "viewuser"),
    631621  OWLCMD_ALIAS("viewperson", "viewuser"),
     
    752742          "no argument, it makes search highlighting inactive."),
    753743
    754   OWLCMD_ARGS("aimlogin", owl_command_aimlogin, OWL_CTX_ANY,
    755               "login to an AIM account",
    756               "aimlogin <screenname> [<password>]\n",
    757               ""),
    758 
    759   OWLCMD_ARGS("aimlogout", owl_command_aimlogout, OWL_CTX_ANY,
    760               "logout from AIM",
    761               "aimlogout\n",
    762               ""),
    763 
    764744  OWLCMD_ARGS("error", owl_command_error, OWL_CTX_ANY,
    765745              "Display an error message",
     
    10881068    }
    10891069  }
    1090   owl_function_buddylist(0, 1, file);
     1070  owl_function_buddylist(1, file);
    10911071  return(NULL);
    10921072}
    10931073
    1094 void owl_command_alist(void)
    1095 {
    1096   owl_function_buddylist(1, 0, NULL);
    1097 }
    1098 
    10991074void owl_command_blist(void)
    11001075{
    1101   owl_function_buddylist(1, 1, NULL);
     1076  owl_function_buddylist(1, NULL);
    11021077}
    11031078
     
    11151090{
    11161091  owl_function_makemsg("BarnOwl version %s", version);
    1117 }
    1118 
    1119 char *owl_command_aim(int argc, const char *const *argv, const char *buff)
    1120 {
    1121   if (argc<2) {
    1122     owl_function_makemsg("not enough arguments to aim command");
    1123     return(NULL);
    1124   }
    1125 
    1126   if (!strcmp(argv[1], "search")) {
    1127     if (argc!=3) {
    1128       owl_function_makemsg("not enough arguments to aim search command");
    1129       return(NULL);
    1130     }
    1131     owl_aim_search(argv[2]);
    1132   } else {
    1133     owl_function_makemsg("unknown subcommand '%s' for aim command", argv[1]);
    1134     return(NULL);
    1135   }
    1136   return(NULL);
    11371092}
    11381093
     
    11441099  }
    11451100
    1146   if (!strcasecmp(argv[1], "aim")) {
    1147     if (!owl_global_is_aimloggedin(&g)) {
    1148       owl_function_makemsg("addbuddy: You must be logged into aim to use this command.");
    1149       return(NULL);
    1150     }
    1151     /*
    1152     owl_function_makemsg("This function is not yet operational.  Stay tuned.");
    1153     return(NULL);
    1154     */
    1155     owl_aim_addbuddy(argv[2]);
    1156     owl_function_makemsg("%s added as AIM buddy for %s", argv[2], owl_global_get_aim_screenname(&g));
    1157   } else if (!strcasecmp(argv[1], "zephyr")) {
     1101  if (!strcasecmp(argv[1], "zephyr")) {
    11581102    owl_zephyr_addbuddy(argv[2]);
    11591103    owl_function_makemsg("%s added as zephyr buddy", argv[2]);
    11601104  } else {
    1161     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'");
    11621106  }
    11631107
     
    11721116  }
    11731117
    1174   if (!strcasecmp(argv[1], "aim")) {
    1175     if (!owl_global_is_aimloggedin(&g)) {
    1176       owl_function_makemsg("delbuddy: You must be logged into aim to use this command.");
    1177       return(NULL);
    1178     }
    1179     owl_aim_delbuddy(argv[2]);
    1180     owl_function_makemsg("%s deleted as AIM buddy for %s", argv[2], owl_global_get_aim_screenname(&g));
    1181   } else if (!strcasecmp(argv[1], "zephyr")) {
     1118  if (!strcasecmp(argv[1], "zephyr")) {
    11821119    owl_zephyr_delbuddy(argv[2]);
    11831120    owl_function_makemsg("%s deleted as zephyr buddy", argv[2]);
    11841121  } else {
    1185     owl_function_makemsg("delbuddy: currently the only supported protocols are 'zephyr' and 'aim'");
    1186   }
    1187 
    1188   return(NULL);
    1189 }
    1190 
    1191 char *owl_command_join(int argc, const char *const *argv, const char *buff)
    1192 {
    1193   if (argc!=3 && argc!=4) {
    1194     owl_function_makemsg("usage: join <protocol> <buddyname> [exchange]");
    1195     return(NULL);
    1196   }
    1197 
    1198   if (!strcasecmp(argv[1], "aim")) {
    1199     if (!owl_global_is_aimloggedin(&g)) {
    1200       owl_function_makemsg("join aim: You must be logged into aim to use this command.");
    1201       return(NULL);
    1202     }
    1203     if (argc==3) {
    1204       owl_aim_chat_join(argv[2], 4);
    1205     } else {
    1206       owl_aim_chat_join(argv[2], atoi(argv[3]));
    1207     }
    1208     /* owl_function_makemsg("%s deleted as AIM buddy for %s", argv[2], owl_global_get_aim_screenname(&g)); */
    1209   } else {
    1210     owl_function_makemsg("join: currently the only supported protocol is 'aim'");
    1211   }
     1122    owl_function_makemsg("delbuddy: currently the only supported protocol is 'zephyr'");
     1123  }
     1124
    12121125  return(NULL);
    12131126}
     
    14351348}
    14361349
     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
    14371369char *owl_command_loadsubs(int argc, const char *const *argv, const char *buff)
    14381370{
     
    15001432
    15011433
    1502 char *owl_command_aaway(int argc, const char *const *argv, const char *buff)
    1503 {
    1504   if ((argc==1) ||
    1505       ((argc==2) && !strcmp(argv[1], "on"))) {
    1506     owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
    1507     owl_function_aaway_on();
    1508     return NULL;
    1509   }
    1510 
    1511   if (argc==2 && !strcmp(argv[1], "off")) {
    1512     owl_function_aaway_off();
    1513     return NULL;
    1514   }
    1515 
    1516   if (argc==2 && !strcmp(argv[1], "toggle")) {
    1517     owl_function_aaway_toggle();
    1518     return NULL;
    1519   }
    1520 
    1521   buff = skiptokens(buff, 1);
    1522   owl_global_set_aaway_msg(&g, buff);
    1523   owl_function_aaway_on();
    1524   return NULL;
    1525 }
    1526 
    1527 
    15281434char *owl_command_away(int argc, const char *const *argv, const char *buff)
    15291435{
     
    15341440      (argc == 2 && !strcmp(argv[1], "on"))) {
    15351441    away_off = false;
    1536     owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
    15371442    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
    15381443  } else if (argc == 2 && !strcmp(argv[1], "off")) {
     
    15461451
    15471452  if (away_off) {
    1548     owl_function_aaway_off();
    15491453    owl_function_zaway_off();
    15501454    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_off", 0, NULL);
    15511455    owl_function_makemsg("Away messages off.");
    15521456  } else if (message != NULL) {
    1553     owl_global_set_aaway_msg(&g, message);
    15541457    owl_global_set_zaway_msg(&g, message);
    1555     owl_function_aaway_on();
    15561458    owl_function_zaway_on();
    15571459    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 1, &message);
    15581460    owl_function_makemsg("Away messages set (%s).", message);
    15591461  } else {
    1560     owl_function_aaway_on();
    15611462    owl_function_zaway_on();
    15621463    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 0, NULL);
     
    19991900  }
    20001901  return(NULL);
    2001 }
    2002 
    2003 char *owl_command_aimwrite(int argc, const char *const *argv, const char *buff)
    2004 {
    2005   char *message = NULL;
    2006   GString *recip = g_string_new("");
    2007   const char *const *myargv;
    2008   int myargc;
    2009  
    2010   if (!owl_global_is_aimloggedin(&g)) {
    2011     owl_function_error("You are not logged in to AIM.");
    2012     goto err;
    2013   }
    2014 
    2015   /* Skip argv[0]. */
    2016   myargv = argv+1;
    2017   myargc = argc-1;
    2018   while (myargc) {
    2019     if (!strcmp(myargv[0], "-m")) {
    2020       if (myargc <= 1) {
    2021         owl_function_error("No message specified.");
    2022         goto err;
    2023       }
    2024       /* Once we have -m, gobble up everything else on the line */
    2025       myargv++;
    2026       myargc--;
    2027       message = g_strjoinv(" ", (char**)myargv);
    2028       break;
    2029     } else {
    2030       /* squish arguments together to make one screenname w/o spaces for now */
    2031       g_string_append(recip, myargv[0]);
    2032       myargv++;
    2033       myargc--;
    2034     }
    2035   }
    2036 
    2037   if (recip->str[0] == '\0') {
    2038     owl_function_error("No recipient specified");
    2039     goto err;
    2040   }
    2041 
    2042   if (message != NULL)
    2043     owl_function_aimwrite(recip->str, message, false);
    2044   else
    2045     owl_function_aimwrite_setup(recip->str);
    2046  err:
    2047   g_string_free(recip, true);
    2048   g_free(message);
    2049   return NULL;
    20501902}
    20511903
     
    26152467}
    26162468
    2617 char *owl_command_aimlogin(int argc, const char *const *argv, const char *buff)
    2618 {
    2619   if ((argc<2) || (argc>3)) {
    2620     owl_function_makemsg("Wrong number of arguments to aimlogin command");
    2621     return(NULL);
    2622   }
    2623 
    2624   /* if we get two arguments, ask for the password */
    2625   if (argc==2) {
    2626     owl_editwin *e = owl_function_start_password("AIM Password: ");
    2627     owl_editwin_set_cbdata(e, g_strdup(argv[1]), g_free);
    2628     owl_editwin_set_callback(e, owl_callback_aimlogin);
    2629     return(NULL);
    2630   } else {
    2631     owl_function_aimlogin(argv[1], argv[2]);
    2632   }
    2633 
    2634   /* this is a test */
    2635   return(NULL);
    2636 }
    2637 
    2638 char *owl_command_aimlogout(int argc, const char *const *argv, const char *buff)
    2639 {
    2640   /* clear the buddylist */
    2641   owl_buddylist_clear(owl_global_get_buddylist(&g));
    2642 
    2643   owl_aim_logout();
    2644   return(NULL);
    2645 }
    2646 
    26472469CALLER_OWN char *owl_command_getstyle(int argc, const char *const *argv, const char *buff)
    26482470{
  • 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 */
  • owl.h

    rca1fb26a r4fd3c04  
    3535#include <termios.h>
    3636#include <unistd.h>
    37 #include "libfaim/aim.h"
    3837#include <wchar.h>
    3938#include <glib.h>
     
    108107#define OWL_EDITWIN_STYLE_MULTILINE 0
    109108#define OWL_EDITWIN_STYLE_ONELINE   1
    110 
    111 #define OWL_PROTOCOL_ZEPHYR         0
    112 #define OWL_PROTOCOL_AIM            1
    113 #define OWL_PROTOCOL_JABBER         2
    114 #define OWL_PROTOCOL_ICQ            3
    115 #define OWL_PROTOCOL_YAHOO          4
    116 #define OWL_PROTOCOL_MSN            5
    117109
    118110#define OWL_MESSAGE_DIRECTION_NONE  0
     
    178170
    179171#define OWL_DEFAULT_ZAWAYMSG    "I'm sorry, but I am currently away from the terminal and am\nnot able to receive your message.\n"
    180 #define OWL_DEFAULT_AAWAYMSG    "I'm sorry, but I am currently away from the terminal and am\nnot able to receive your message.\n"
    181172
    182173#define OWL_CMD_ALIAS_SUMMARY_PREFIX "command alias to: "
     
    492483  int       kpstackpos;         /* location in stack (-1 = none) */
    493484} owl_keyhandler;
    494 
    495 typedef struct _owl_buddy {
    496   int proto;
    497   char *name;
    498   int isidle;
    499   int idlesince;
    500 } owl_buddy;
    501 
    502 typedef struct _owl_buddylist {
    503   GPtrArray *buddies;
    504 } owl_buddylist;
    505485
    506486typedef struct _owl_zbuddylist {
     
    569549  pid_t newmsgproc_pid;
    570550  owl_regex search_re;
    571   aim_session_t aimsess;
    572   aim_conn_t bosconn;
    573   int aim_loggedin;         /* true if currently logged into AIM */
    574   GSource *aim_event_source; /* where we get our AIM events from */
    575   char *aim_screenname;     /* currently logged in AIM screen name */
    576   char *aim_screenname_for_filters;     /* currently logged in AIM screen name */
    577   owl_buddylist buddylist;  /* list of logged in AIM buddies */
    578   GQueue *messagequeue;     /* for queueing up aim and other messages */
     551  GQueue *messagequeue;     /* for queueing up messages */
    579552  owl_dict styledict;       /* global dictionary of available styles */
    580553  char *response;           /* response to the last question asked */
    581554  int havezephyr;
    582   int haveaim;
    583   int ignoreaimlogin;
    584555  owl_zbuddylist zbuddies;
    585556  GList *zaldlist;
    586557  int pseudologin_notify;
    587558  struct termios startup_tio;
    588   guint aim_nop_timer;
    589559  int load_initial_subs;
    590560  FILE *debug_file;
  • 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.pm

    recd4edf reea7bed4  
    1616                    create_style getnumcolors wordwrap
    1717                    message_matches_filter
     18                    get_variable_info
    1819                    add_dispatch remove_dispatch
    1920                    add_io_dispatch remove_io_dispatch
     
    3839use BarnOwl::Hook;
    3940use BarnOwl::Hooks;
     41use BarnOwl::Logging;
    4042use BarnOwl::Message;
    4143use BarnOwl::Style;
     
    4547use BarnOwl::Completion;
    4648use BarnOwl::Help;
     49use BarnOwl::DeferredLogging;
    4750
    4851use List::Util qw(max);
     
    249252C<QUIET> is false, this method displays an error message if
    250253if C<FILTER_NAME> does not name a valid filter.
     254
     255=head2 get_variable_info VARIABLE_NAME
     256
     257Returns a hash with the following keys, describing the variable named:
     258
     259=over
     260
     261=item name
     262
     263=item description
     264
     265=item summary
     266
     267=item validsettings
     268
     269=item takes_on_off
     270
     271=back
     272
     273Fails if C<VARIABLE_NAME> does not name a valid variable.
    251274
    252275=head2 add_dispatch FD CALLBACK
  • 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/IRC/lib/BarnOwl/Module/IRC.pm

    r926c721 rd4f33f1  
    562562                               "[" . $conn->alias . "] Reconnect cancelled");
    563563        $conn->cancel_reconnect;
     564        delete $ircnets{$conn->alias};
     565    } elsif (exists $ircnets{$conn->alias}) { # inconsistent state; no socket, but not yet deleted
     566        BarnOwl::admin_message('IRC',
     567                               "[" . $conn->alias . "] Attempt to disconnect from a socketless connection; deleting it");
    564568        delete $ircnets{$conn->alias};
    565569    }
  • perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm

    rbe43554 r4379288  
    437437}
    438438
     439sub rejoin_channels {
     440    my $self = shift;
     441    my @channels = @_;
     442    # As reported in https://barnowl.mit.edu/ticket/274, if we reconnect to
     443    # too many at once, the server rejects us.  Empirically, this is about
     444    # 20-26, so we set the cap at 15, then delay further joins for 5 seconds.
     445    my $MAX_RECONNECT_CHANNELS = 15;
     446    my $DELAY = 5;
     447    foreach my $c (@channels[ 0 .. $MAX_RECONNECT_CHANNELS ]) {
     448        $self->conn->send_msg(join => $c);
     449    }
     450    if ($MAX_RECONNECT_CHANNELS < $#channels) {
     451        my $remaining = $#channels - $MAX_RECONNECT_CHANNELS;
     452        my $cur_alias = $self->alias;
     453        BarnOwl::admin_message('IRC', "[$cur_alias] Delaying $remaining autorejoins for $DELAY seconds");
     454        # if we don't assign the timer to anything, then it gets garbage
     455        # collected, and never runs
     456        $self->{autoconnect_channels_delay_timer} = BarnOwl::Timer->new({
     457            name  => "IRC rejoin overflow timer ($remaining remaining)",
     458            after => $DELAY,
     459            cb    => sub {
     460                rejoin_channels($self, @channels[ $MAX_RECONNECT_CHANNELS .. $#channels ]);
     461            }
     462        });
     463    }
     464}
     465
     466
    439467sub connected {
    440468    my $self = shift;
     
    443471    $self->cancel_reconnect;
    444472    if ($self->autoconnect_channels) {
    445         for my $c (@{$self->autoconnect_channels}) {
    446             $self->conn->send_msg(join => $c);
    447         }
     473        rejoin_channels($self, @{$self->autoconnect_channels});
    448474    }
    449475    $self->conn->enable_ping(60, sub {
  • 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);
  • perlglue.xs

    r7dcef03 rd2ba33c  
    385385                RETVAL
    386386
     387SV *
     388get_variable_info(name)
     389        const char *name;
     390        PREINIT:
     391                owl_variable *var;
     392                HV *h;
     393        CODE:
     394                var = owl_variable_get_var(owl_global_get_vardict(&g), name);
     395                if (var == NULL) {
     396                        croak("No such variable");
     397                }
     398                h = newHV();
     399                (void)hv_store(h, "name", strlen("name"),
     400                               owl_new_sv(owl_variable_get_name(var)), 0);
     401                (void)hv_store(h, "description", strlen("description"),
     402                               owl_new_sv(owl_variable_get_description(var)),
     403                               0);
     404                (void)hv_store(h, "summary", strlen("summary"),
     405                               owl_new_sv(owl_variable_get_summary(var)), 0);
     406                (void)hv_store(h, "validsettings", strlen("validsettings"),
     407                               owl_new_sv(owl_variable_get_validsettings(var)),
     408                               0);
     409                (void)hv_store(h, "takes_on_off", strlen("takes_on_off"),
     410                               newSViv(owl_variable_takes_on_off(var)), 0);
     411                RETVAL = newRV_noinc((SV*)h);
     412        OUTPUT:
     413                RETVAL
     414
     415const utf8 *
     416compat_casefold(in)
     417        const char * in
     418        PREINIT:
     419                char *rv;
     420        CODE:
     421                rv = owl_util_compat_casefold(in);
     422                RETVAL = rv;
     423        OUTPUT:
     424                RETVAL
     425        CLEANUP:
     426                g_free(rv);
     427
    387428
    388429MODULE = BarnOwl                PACKAGE = BarnOwl::Zephyr
     
    407448        OUTPUT:
    408449                RETVAL
     450
     451const utf8 *
     452makepath(in)
     453        const char * in
     454        PREINIT:
     455                char *rv;
     456        CODE:
     457                rv = owl_util_makepath(in);
     458                RETVAL = rv;
     459        OUTPUT:
     460                RETVAL
     461        CLEANUP:
     462                g_free(rv);
    409463
    410464void
     
    642696        OUTPUT:
    643697                RETVAL
     698
     699MODULE = BarnOwl                PACKAGE = BarnOwl::Logging
     700
     701void
     702enqueue_text(log_text, filename)
     703        const char * log_text
     704        const char * filename
     705        CODE:
     706                owl_log_enqueue_message(log_text, filename);
  • 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
  • tester.c

    r21dc927 ra882637  
    8282    sv_setpv(get_sv("main::test_prog", TRUE), argv[1]);
    8383
    84     eval_pv("do $main::test_prog; die($@) if($@)", true);
    85   }
    86 
    87   status = 0;
     84    eval_pv("use File::Spec; do File::Spec->rel2abs($main::test_prog); die($@) if($@)", true);
     85  }
    8886
    8987  FREETMPS;
     
    357355
    358356
    359   FAIL_UNLESS("get string var", NULL != (var = owl_variable_get_var(&vd, "logpath")));
    360   FAIL_UNLESS("get string", 0 == strcmp("~/zlog/people", owl_variable_get_string(var)));
     357  FAIL_UNLESS("get string var", NULL != (var = owl_variable_get_var(&vd, "personalbell")));
     358  FAIL_UNLESS("get string", 0 == strcmp("off", owl_variable_get_string(var)));
    361359  FAIL_UNLESS("set string 7", 0 == owl_variable_set_string(var, "whee"));
    362360  FAIL_UNLESS("get string", !strcmp("whee", owl_variable_get_string(var)));
  • 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

    r18380fd 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);
     
    13111311{
    13121312  int n = strcspn(in, "./");
    1313   char *realm = strchrnul(in, '@');
     1313  const char *realm = strchr(in, '@');
     1314  if (realm == NULL)
     1315    realm = in + strlen(in);
    13141316
    13151317  if (in + n >= realm ||
  • 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.