Changes in / [ba52ac5:537d9b9]
- Files:
-
- 4 added
- 70 edited
Legend:
- Unmodified
- Added
- Removed
-
.travis.yml
rba52ac5 r537d9b9 3 3 4 4 script: 5 - ./configure 5 - ./configure --pam=1 --ldap=1 6 6 - make check 7 7 - BITLBEE_SKYPE=plugin dpkg-buildpackage -uc -us -d … … 29 29 - libpurple-dev 30 30 - check 31 - libpam0g-dev 32 - libldap2-dev 31 33 coverity_scan: 32 34 project: … … 34 36 description: "An IRC to other chat networks gateway" 35 37 notification_email: dx@dxzone.com.ar 36 build_command_prepend: ./configure --otr=1 --debug=1 38 build_command_prepend: ./configure --otr=1 --debug=1 --pam=1 --ldap=1 37 39 build_command: make 38 40 branch_pattern: coverity_scan -
Makefile
rba52ac5 r537d9b9 10 10 11 11 # Program variables 12 objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_cap.o irc_channel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o $(OTR_BI) query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o conf.o log.o12 objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_cap.o irc_channel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o $(OTR_BI) query.o root_commands.o set.o storage.o $(STORAGE_OBJS) auth.o $(AUTH_OBJS) unix.o conf.o log.o 13 13 headers = $(wildcard $(_SRCDIR_)*.h $(_SRCDIR_)lib/*.h $(_SRCDIR_)protocols/*.h) 14 14 subdirs = lib protocols -
bitlbee.conf
rba52ac5 r537d9b9 52 52 # AuthMode = Open 53 53 54 ## AuthBackend 55 ## 56 ## By default, the authentication data for a user is stored in the storage 57 ## backend. If you want to authenticate against another authentication system 58 ## (e.g. ldap), you can specify that here. 59 ## 60 ## Beware that this disables password changes and causes passwords for the 61 ## accounts people create to be stored in plain text instead of encrypted with 62 ## their bitlbee password. 63 ## 64 ## Currently available backends: 65 ## 66 ## - storage (internal storage) 67 ## - pam (Linux PAM authentication) 68 ## - ldap (LDAP server configured in the openldap settings) 69 # 70 # AuthBackend = storage 71 # 72 54 73 ## AuthPassword 55 74 ## … … 69 88 ## or 70 89 # OperPassword = md5:I0mnZbn1t4R731zzRdDN2/pK7lRX 90 91 ## AllowAccountAdd 92 ## 93 ## Whether to allow registered and identified users to add new accounts using 94 ## 'account add' 95 ## 96 # AllowAccountAdd 1 71 97 72 98 ## HostName -
bitlbee.h
rba52ac5 r537d9b9 36 36 37 37 #define PACKAGE "BitlBee" 38 #define BITLBEE_VERSION "3.4. 1"38 #define BITLBEE_VERSION "3.4.2" 39 39 #define VERSION BITLBEE_VERSION 40 40 #define BITLBEE_VER(a, b, c) (((a) << 16) + ((b) << 8) + (c)) 41 #define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 1) 41 #define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 2) 42 #define BITLBEE_ABI_VERSION_CODE 1 42 43 43 44 #define MAX_STRING 511 … … 133 134 #include "irc.h" 134 135 #include "storage.h" 136 #include "auth.h" 135 137 #include "set.h" 136 138 #include "nogaim.h" … … 154 156 conf_t *conf; 155 157 GList *storage; /* The first backend in the list will be used for saving */ 158 GList *auth; /* Authentication backends */ 156 159 char *helpfile; 157 160 int restart; … … 170 173 gboolean root_command_add(const char *command, int params, void (*func)(irc_t *, char **args), int flags); 171 174 gboolean cmd_identify_finish(gpointer data, gint fd, b_input_condition cond); 175 void cmd_chat_list_finish(struct im_connection *ic); 172 176 gboolean bitlbee_shutdown(gpointer data, gint fd, b_input_condition cond); 173 177 -
conf.c
rba52ac5 r537d9b9 55 55 conf->runmode = RUNMODE_INETD; 56 56 conf->authmode = AUTHMODE_OPEN; 57 conf->auth_backend = NULL; 57 58 conf->auth_pass = NULL; 58 59 conf->oper_pass = NULL; 60 conf->allow_account_add = 1; 59 61 conf->configdir = g_strdup(CONFIG); 60 62 conf->plugindir = g_strdup(PLUGINDIR); … … 240 242 conf->authmode = AUTHMODE_OPEN; 241 243 } 244 } else if (g_strcasecmp(ini->key, "authbackend") == 0) { 245 if (g_strcasecmp(ini->value, "storage") == 0) { 246 conf->auth_backend = NULL; 247 } else if (g_strcasecmp(ini->value, "pam") == 0 || 248 g_strcasecmp(ini->value, "ldap") == 0) { 249 g_free(conf->auth_backend); 250 conf->auth_backend = g_strdup(ini->value); 251 } else { 252 fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value); 253 return 0; 254 } 242 255 } else if (g_strcasecmp(ini->key, "authpassword") == 0) { 243 256 g_free(conf->auth_pass); … … 246 259 g_free(conf->oper_pass); 247 260 conf->oper_pass = g_strdup(ini->value); 261 } else if (g_strcasecmp(ini->key, "allowaccountadd") == 0) { 262 if (!is_bool(ini->value)) { 263 fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value); 264 return 0; 265 } 266 conf->allow_account_add = bool2int(ini->value); 248 267 } else if (g_strcasecmp(ini->key, "hostname") == 0) { 249 268 g_free(conf->hostname); -
conf.h
rba52ac5 r537d9b9 37 37 runmode_t runmode; 38 38 authmode_t authmode; 39 char *auth_backend; 39 40 char *auth_pass; 40 41 char *oper_pass; 42 int allow_account_add; 41 43 char *hostname; 42 44 char *configdir; -
configure
rba52ac5 r537d9b9 54 54 ssl=auto 55 55 56 pam=0 57 ldap=0 58 56 59 pie=1 57 60 58 61 arch=$(uname -s) 59 cpu=$(uname -m)60 62 61 63 GLIB_MIN_VERSION=2.16 … … 138 140 --rpc=0/1 Disable/enable RPC plugin interface $rpc 139 141 142 --pam=0/1 Disable/enable PAM authentication $pam 143 --ldap=0/1 Disable/enable LDAP authentication $ldap 144 140 145 --doc=0/1 Disable/enable help.txt generation $doc 141 146 --debug=0/1 Disable/enable debugging $debug … … 200 205 201 206 TARGET=$target 202 ARCH=$arch203 CPU=$cpu204 207 205 208 INSTALL=install -p … … 249 252 #define PIDFILE "$pidfile" 250 253 #define IPCSOCKET "$ipcsocket" 251 #define ARCH "$arch"252 #define CPU "$cpu"253 254 EOF 254 255 … … 348 349 fi 349 350 350 if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG glib-2.0; then 351 if ! $PKG_CONFIG --version > /dev/null 2>/dev/null; then 352 echo 353 echo 'Cannot find pkg-config, aborting.' 354 exit 1 355 fi 356 357 if $PKG_CONFIG glib-2.0; then 351 358 if $PKG_CONFIG glib-2.0 --atleast-version=$GLIB_MIN_VERSION; then 352 359 cat<<EOF >>Makefile.settings … … 641 648 done 642 649 echo "STORAGE_OBJS="$STORAGE_OBJS >> Makefile.settings 650 651 authobjs= 652 authlibs= 653 if [ "$pam" = 0 ]; then 654 echo '#undef WITH_PAM' >> config.h 655 else 656 if ! echo '#include <security/pam_appl.h>' | $CC -E - >/dev/null 2>/dev/null; then 657 echo 'Cannot find libpam development libraries, aborting. (Install libpam0g-dev?)' 658 exit 1 659 fi 660 echo '#define WITH_PAM' >> config.h 661 authobjs=$authobjs'auth_pam.o ' 662 authlibs=$authlibs'-lpam ' 663 fi 664 if [ "$ldap" = 0 ]; then 665 echo '#undef WITH_LDAP' >> config.h 666 else 667 if ! echo '#include <ldap.h>' | $CC -E - >/dev/null 2>/dev/null; then 668 echo 'Cannot find libldap development libraries, aborting. (Install libldap2-dev?)' 669 exit 1 670 fi 671 echo '#define WITH_LDAP' >> config.h 672 authobjs=$authobjs'auth_ldap.o ' 673 authlibs=$authlibs'-lldap ' 674 fi 675 echo AUTH_OBJS=$authobjs >> Makefile.settings 676 echo EFLAGS+=$authlibs >> Makefile.settings 643 677 644 678 if [ "$strip" = 0 ]; then -
debian/bitlbee-common.postinst
rba52ac5 r537d9b9 9 9 10 10 CONFDIR=/var/lib/bitlbee/ 11 12 update-rc.d bitlbee defaults > /dev/null 2>&113 11 14 12 ## Load default option. Don't want to put this in debconf (yet?) … … 66 64 fi 67 65 68 if [ "$BITLBEE_UPGRADE_DONT_RESTART" != "1" -a -n "$2" ]; then66 if [ "$BITLBEE_UPGRADE_DONT_RESTART" != "1" -a -n "$2" -a -x "/etc/init.d/bitlbee" ]; then 69 67 invoke-rc.d bitlbee restart 70 68 fi … … 92 90 fi 93 91 94 if [ -z "$2" ]; then 95 invoke-rc.d bitlbee start 96 fi 92 #DEBHELPER# -
debian/bitlbee-common.postrm
rba52ac5 r537d9b9 3 3 set -e 4 4 5 [ "$1" = "purge" ] || exit 0 6 7 if [ -e /usr/share/debconf/confmodule ]; then 8 . /usr/share/debconf/confmodule; 9 db_purge; 5 if [ "$1" = "purge" ]; then 6 rm -f /etc/default/bitlbee 7 deluser --system bitlbee || true 8 rm -rf /var/lib/bitlbee ## deluser doesn't seem to do this for homedirs in /var 10 9 fi 11 10 12 update-rc.d bitlbee remove > /dev/null 2>&1 || true 13 rm -f /etc/default/bitlbee 14 15 deluser --system bitlbee || true 16 rm -rf /var/lib/bitlbee ## deluser doesn't seem to do this for homedirs in /var 11 #DEBHELPER# -
debian/bitlbee-common.prerm
rba52ac5 r537d9b9 11 11 mv /usr/share/bitlbee/help.txt /usr/share/bitlbee/help.upgrading 12 12 fi 13 else14 invoke-rc.d bitlbee stop15 13 fi 14 15 #DEBHELPER# -
debian/bitlbee.prerm
rba52ac5 r537d9b9 6 6 invoke-rc.d bitlbee stop 7 7 fi 8 9 #DEBHELPER# -
debian/changelog
rba52ac5 r537d9b9 1 bitlbee (3.4.2-1) unstable; urgency=medium 2 3 [ Jelmer Vernooij ] 4 * Make the build reproducible by not encoding ARCH / CPU defines in 5 the binary. 6 * Fix Vcs-* control headers after migration to Git. 7 * Don't start synopsis with an article. 8 * Bump standards version to 3.9.8 (no changes). 9 * Use dh_prep rather than deprecated 'dh_clean -k'. 10 11 [ Wilmer van der Gaast ] 12 * New upstream release. 13 14 -- Wilmer van der Gaast <wilmer@gaast.net> Sun, 12 Jun 2016 22:31:18 +0100 15 1 16 bitlbee (3.4.1-1) unstable; urgency=medium 2 17 -
debian/control
rba52ac5 r537d9b9 3 3 Priority: optional 4 4 Maintainer: Wilmer van der Gaast <wilmer@gaast.net> 5 Uploaders: Jelmer Vernoo ij<jelmer@debian.org>6 Standards-Version: 3.9. 57 Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls28-dev | libgnutls-dev | gnutls-dev, po-debconf, libpurple-dev, libotr5-dev, debhelper (>= 6.0.7~) 5 Uploaders: Jelmer Vernooij <jelmer@debian.org> 6 Standards-Version: 3.9.8 7 Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls28-dev | libgnutls-dev | gnutls-dev, po-debconf, libpurple-dev, libotr5-dev, debhelper (>= 6.0.7~), dh-systemd (>= 1.5) | debhelper (<< 9.20131227) 8 8 Homepage: http://www.bitlbee.org/ 9 Vcs-Bzr: http://code.bitlbee.org/bitlbee/ 9 Vcs-Git: https://github.com/bitlbee/bitlbee 10 Vcs-Browser: https://github.com/bitlbee/bitlbee 10 11 11 12 Package: bitlbee … … 14 15 Conflicts: bitlbee-libpurple 15 16 Replaces: bitlbee-libpurple 16 Description: AnIRC to other chat networks gateway (default version)17 Description: IRC to other chat networks gateway (default version) 17 18 This program can be used as an IRC server which forwards everything you 18 19 say to people on other chat networks: Jabber (which includes Google Talk … … 24 25 Conflicts: bitlbee 25 26 Replaces: bitlbee 26 Description: AnIRC to other chat networks gateway (using libpurple)27 Description: IRC to other chat networks gateway (using libpurple) 27 28 This program can be used as an IRC server which forwards everything you 28 29 say to people on other chat networks: Jabber (which includes Google Talk … … 40 41 Depends: ${misc:Depends}, net-tools, adduser 41 42 Replaces: bitlbee 42 Description: AnIRC to other chat networks gateway (common files/docs)43 Description: IRC to other chat networks gateway (common files/docs) 43 44 This program can be used as an IRC server which forwards everything you 44 45 say to people on other chat networks: Jabber (which includes Google Talk … … 51 52 Architecture: all 52 53 Depends: ${misc:Depends}, bitlbee (>= ${source:Version}) | bitlbee-libpurple (>= ${source:Version}), bitlbee (<< ${source:Version}.1~) | bitlbee-libpurple (<< ${source:Version}.1~), bitlbee-common (= ${source:Version}) 53 Description: AnIRC to other chat networks gateway (dev files)54 Description: IRC to other chat networks gateway (dev files) 54 55 This program can be used as an IRC server which forwards everything you 55 56 say to people on other chat networks: Jabber (which includes Google Talk … … 61 62 Architecture: any 62 63 Depends: ${misc:Depends}, ${shlibs:Depends}, bitlbee (= ${binary:Version}) | bitlbee-libpurple (= ${binary:Version}), bitlbee-common (= ${source:Version}) 63 Description: AnIRC to other chat networks gateway (OTR plugin)64 Description: IRC to other chat networks gateway (OTR plugin) 64 65 This program can be used as an IRC server which forwards everything you 65 66 say to people on other chat networks: Jabber (which includes Google Talk … … 73 74 Depends: ${misc:Depends}, ${shlibs:Depends}, bitlbee (= ${binary:Version}) | bitlbee-libpurple (= ${binary:Version}), bitlbee-common (= ${source:Version}) 74 75 Recommends: skyped 75 Description: AnIRC to other chat networks gateway (Skype plugin)76 Description: IRC to other chat networks gateway (Skype plugin) 76 77 This program can be used as an IRC server which forwards everything you 77 78 say to people on other chat networks: Jabber (which includes Google Talk -
debian/rules
rba52ac5 r537d9b9 40 40 CONFIGURE_OVERRIDES:=CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" 41 41 42 HAS_DH_SYSTEMD:=$(shell dpkg-query -W -f='$${Status}' dh-systemd 2>/dev/null | grep -c "ok installed") 43 42 44 build: build-stamp 43 45 build-stamp: … … 72 74 dh_testdir 73 75 dh_testroot 74 dh_ clean -k76 dh_prep 75 77 dh_installdirs 76 78 … … 80 82 $(MAKE) -C debian/build-native install-plugin-otr DESTDIR=`pwd`/debian/bitlbee-plugin-otr 81 83 $(MAKE) -C debian/build-native install-plugin-skype DESTDIR=`pwd`/debian/skyped 84 85 ifeq ($(HAS_DH_SYSTEMD),1) 86 $(MAKE) -C debian/build-native install-systemd DESTDIR=`pwd`/debian/bitlbee-common 87 endif 82 88 83 89 ifneq ($(BITLBEE_SKYPE),0) … … 108 114 for p in bitlbee bitlbee-libpurple bitlbee-dev bitlbee-plugin-otr; do rm -r debian/$$p/usr/share/doc/$$p && ln -s bitlbee-common debian/$$p/usr/share/doc/$$p || true; done 109 115 dh_installdebconf 116 ifeq ($(HAS_DH_SYSTEMD),1) 117 dh_systemd_enable 110 118 dh_installinit --init-script=bitlbee 119 dh_systemd_start 120 else 121 dh_installinit --init-script=bitlbee 122 endif 111 123 dh_installman 112 124 dh_lintian -
doc/CHANGES
rba52ac5 r537d9b9 3 3 4 4 https://github.com/bitlbee/bitlbee/commits/master 5 6 Version 3.4.2: 7 - irc: 8 * Self-messages (messages sent by yourself from other IM clients), given 9 support by the IM protocols and your IRC client. See this for details: 10 https://wiki.bitlbee.org/SelfMessages 11 * IRCv3.1 support and part of 3.2: cap-3.2, sasl-3.2, multi-prefix, 12 away-notify, extended-join, userhost-in-names 13 * Send numeric errors when failing to join a channel, to not confuse clients 14 * Channel autojoins should be more reliable now. 15 - jabber: 16 * Carbons (XEP-0280), for self-message support. It's not widely supported 17 by most public XMPP servers (easier if you host your own), but this will 18 probably change in the next few years. Thanks kormat for the original patch. 19 * Fix typing notifications between two bitlbee users or with gtalk users 20 * Remove facebook XMPP code, point people at bitlbee-facebook. 21 * Show groupchat kick/ban/leave reasons 22 * SASL ANONYMOUS (XEP-0175), for "guest" logins, see "help set anonymous" 23 * Hipchat: 'chat add hipchat "channel name"' now tries to guess the JID 24 - purple: 25 * Fix problems remembering SSL certificates as trusted 26 * Fix /join #channel, which joined a differently named channel 27 * Fix crash when doing "chat with" with skypeweb 28 * Fix html entities appearing in some protocols 29 * Fix setting away states in jabber, which failed silently 30 * Implement notify_message UI op, to be able to show some error messages. 31 - skype: 32 * Show all messages as groupchats since we can't tell which ones are private. 33 * This plugin is mostly-deprecated and mostly-broken but it's still useful 34 for p2p-based groupchats, which aren't delivered over newer protocols. 35 Everyone else should use the skypeweb purple plugin or msn instead. 36 - msn: 37 * Minor tweaks. Faster login, better error reporting, fixed add/remove. 38 Still MSNP21. Disregard that "Next release!" in the previous release. 39 - otr: 40 * Don't use NOTICE for user messages (revmischa) 41 * Fix crashes when using the jabber xmlconsole 42 * A few minor fixes: color multiline messages, filter incoming color codes. 43 - Packaging: 44 * Show ./configure args in bitlbee -V, config.h and Makefile.settings 45 * Allow setting the plugin dir in bitlbee.conf, for NixOS (anderspapitto) 46 * Improved cross compiler support (gamaral) 47 - Other important bugfixes: 48 * Fix potential crashes when leaving temporary channels 49 * Fix all sorts of crashing bugs when cancelling in-progress connections. 50 51 Finished 19 Mar 2016 5 52 6 53 Version 3.4.1: -
doc/user-guide/commands.xml
rba52ac5 r537d9b9 258 258 259 259 <para> 260 Available actions: add, with . See <emphasis>help chat <action></emphasis> for more information.260 Available actions: add, with, list. See <emphasis>help chat <action></emphasis> for more information. 261 261 </para> 262 262 … … 264 264 265 265 <bitlbee-command name="add"> 266 <syntax>chat add <account id> <room > [<channel>]</syntax>266 <syntax>chat add <account id> <room|!index> [<channel>]</syntax> 267 267 268 268 <description> … … 272 272 273 273 <para> 274 After adding a room to your list, you can simply use the IRC /join command to enter the room. Also, you can tell BitlBee to automatically join the room when you log in. ( See <emphasis>chat set</emphasis>)274 After adding a room to your list, you can simply use the IRC /join command to enter the room. Also, you can tell BitlBee to automatically join the room when you log in. (<emphasis>channel <channel> set auto_join true</emphasis>) 275 275 </para> 276 276 … … 280 280 </description> 281 281 282 </bitlbee-command> 283 284 <bitlbee-command name="list"> 285 <syntax>chat list <account id> [<server>]</syntax> 286 287 <description> 288 <para> 289 List existing chatrooms provided by an account. BitlBee needs this to propogate an internal list of chats. The existing chat can then be added with <emphasis>chat add</emphasis>, using the number in the index column after a "!" as a shortcut. 290 </para> 291 </description> 292 293 <ircexample> 294 <ircline nick="dx">chat list facebook</ircline> 295 <ircline pre="1" nick="root">Index Title Topic</ircline> 296 <ircline pre="1" nick="root"> 1 869891016470949 cool kids club</ircline> 297 <ircline pre="1" nick="root"> 2 457892181062459 uncool kids club</ircline> 298 <ircline nick="root">2 facebook chatrooms</ircline> 299 <ircline nick="dx">chat add facebook !1 #cool-kids-club</ircline> 300 </ircexample> 282 301 </bitlbee-command> 283 302 … … 288 307 <para> 289 308 While most <emphasis>chat</emphasis> subcommands are about named chatrooms, this command can be used to open an unnamed groupchat with one or more persons. This command is what <emphasis>/join #nickname</emphasis> used to do in older BitlBee versions. 309 </para> 310 311 <para> 312 Another way to do this is to join to a new, empty channel with <emphasis>/join #newchannel</emphasis> and invite the first person with <emphasis>/invite nickname</emphasis> 290 313 </para> 291 314 </description> … … 645 668 <para> 646 669 When you're already connected to a BitlBee server and you connect (and identify) again, BitlBee will offer to migrate your existing session to the new connection. If for whatever reason you don't want this, you can disable this setting. 670 </para> 671 </description> 672 </bitlbee-setting> 673 674 <bitlbee-setting name="always_use_nicks" type="boolean" scope="channel"> 675 <default>false</default> 676 677 <description> 678 <para> 679 Jabber groupchat specific. This setting ensures that the nicks defined by the other members of a groupchat are used, instead of the username part of their JID. This only applies to groupchats where their real JID is known (either "non-anonymous" ones, or "semi-anonymous" from the point of view of the channel moderators) 680 </para> 681 682 <para> 683 Enabling this may have the side effect of changing the nick of existing contacts, either in your buddy list or in other groupchats. If a contact is in multiple groupchats with different nicks, enabling this setting for all those would result in multiple nick changes when joining, and the order of those changes may vary. 684 </para> 685 686 <para> 687 Note that manual nick changes done through the <emphasis>rename</emphasis> command always take priority 647 688 </para> 648 689 </description> … … 1491 1532 and any modes they should have. The following statuses are currently 1492 1533 recognised: <emphasis>online</emphasis> (i.e. available, not 1493 away), <emphasis>special</emphasis> , <emphasis>away</emphasis>,1494 and <emphasis>offline</emphasis>.1534 away), <emphasis>special</emphasis> (specific to the protocol), 1535 <emphasis>away</emphasis>, and <emphasis>offline</emphasis>. 1495 1536 </para> 1496 1537 … … 1498 1539 If a status is followed by a valid channel mode character 1499 1540 (@, % or +), it will be given to users with that status. 1500 For example, <emphasis>online@,special%,away+,offline</emphasis> 1541 For example, <emphasis>online@,special%,away+,offline</emphasis> 1501 1542 will show all users in the channel. Online people will 1502 1543 have +o, people who are online but away will have +v, … … 1815 1856 </para> 1816 1857 </description> 1858 </bitlbee-command> 1859 1860 <bitlbee-command name="plugins"> 1861 <short-description>List all the external plugins and protocols</short-description> 1862 <syntax>plugins</syntax> 1863 1864 <description> 1865 <para> 1866 This gives you a list of all the external plugins and protocols. 1867 </para> 1868 </description> 1869 1817 1870 </bitlbee-command> 1818 1871 -
doc/user-guide/genhelp.py
rba52ac5 r537d9b9 65 65 66 66 # Actually normalize whitespace 67 tag.text = normalize(tag.text) 67 if 'pre' not in tag.attrib: 68 tag.text = normalize(tag.text) 68 69 tag.tail = normalize(tag.tail) 69 70 -
doc/user-guide/misc.xml
rba52ac5 r537d9b9 445 445 </sect1> 446 446 447 <sect1 id="whatsnew030402"> 448 <title>New stuff in BitlBee 3.4.2</title> 449 450 <simplelist> 451 <member><emphasis>irc:</emphasis> Self-messages (messages sent by yourself from other IM clients), see <emphasis>help set self_messages</emphasis>. IRCv3.1 support and part of 3.2. Many important groupchat related bugfixes.</member> 452 <member><emphasis>jabber:</emphasis> Carbons, see <emphasis>help set carbons</emphasis>. Removed facebook XMPP, use bitlbee-facebook instead. SASL ANONYMOUS login, see <emphasis>help set anonymous</emphasis>.</member> 453 <member><emphasis>hipchat:</emphasis> Channels can now be added with <emphasis>chat add hipchat "channel name"</emphasis> which tries to guess the channel JID.</member> 454 <member><emphasis>skype:</emphasis> Show all messages as groupchats since we can't tell which ones are private. This plugin is mostly-deprecated and mostly-broken, use the skypeweb purple plugin or msn instead.</member> 455 <member><emphasis>purple:</emphasis> Fix problems remembering SSL certificates as trusted. Groupchat related fixes. Better error reporting. Fixed setting jabber away states.</member> 456 </simplelist> 457 458 <para> 459 And lots of bugfixes / stability improvements. See the full changelog for details! 460 </para> 461 462 </sect1> 463 447 464 </chapter> -
init/bitlbee.service.in
rba52ac5 r537d9b9 5 5 [Service] 6 6 ExecStart=@sbindir@bitlbee -F -n 7 KillMode=process 7 8 8 9 [Install] -
irc.h
rba52ac5 r537d9b9 29 29 #define IRC_MAX_LINE 512 30 30 #define IRC_MAX_ARGS 16 31 #define IRC_WORD_WRAP 425 31 32 32 33 #define IRC_LOGIN_TIMEOUT 60 … … 92 93 logging in, this may contain a password we should 93 94 send to identify after USER/NICK are received. */ 95 char *auth_backend; 94 96 95 97 char umode[8]; -
irc_cap.c
rba52ac5 r537d9b9 177 177 178 178 } else if (g_strcasecmp(cmd[1], "END") == 0) { 179 if (!(irc->status & USTATUS_CAP_PENDING)) { 180 return; 181 } 179 182 irc->status &= ~USTATUS_CAP_PENDING; 180 183 -
irc_channel.c
rba52ac5 r537d9b9 245 245 ic->users = g_slist_insert_sorted(ic->users, icu, irc_channel_user_cmp); 246 246 247 irc_channel_update_ops(ic, set_getstr(&ic->irc->b->set, "ops")); 247 if (iu == ic->irc->user || iu == ic->irc->root) { 248 irc_channel_update_ops(ic, set_getstr(&ic->irc->b->set, "ops")); 249 } 248 250 249 251 if (iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED) { -
irc_commands.c
rba52ac5 r537d9b9 97 97 /* just check the password here to be able to reply with useful numerics 98 98 * the actual identification will be handled later */ 99 status = storage_check_pass(user, pass);99 status = auth_check_pass(irc, user, pass); 100 100 101 101 if (status == STORAGE_OK) { … … 767 767 static void irc_cmd_version(irc_t *irc, char **cmd) 768 768 { 769 irc_send_num(irc, 351, "%s-%s. %s : %s/%s",770 PACKAGE, BITLBEE_VERSION, irc->root->host , ARCH, CPU);769 irc_send_num(irc, 351, "%s-%s. %s :", 770 PACKAGE, BITLBEE_VERSION, irc->root->host); 771 771 } 772 772 -
irc_im.c
rba52ac5 r537d9b9 120 120 } 121 121 122 if ((irc->caps & CAP_AWAY_NOTIFY) &&123 ((bu->flags & BEE_USER_AWAY) != (old->flags & BEE_USER_AWAY) ||124 (bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE))) {125 irc_send_away_notify(iu);126 }127 128 122 if ((bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE)) { 129 123 if (bu->flags & BEE_USER_ONLINE) { … … 153 147 154 148 bee_irc_channel_update(irc, NULL, iu); 149 150 /* If away-notify enabled, send status updates when: 151 * Away or Online state changes 152 * Status changes (e.g. "Away" to "Mobile") 153 * Status message changes 154 */ 155 if ((irc->caps & CAP_AWAY_NOTIFY) && 156 ((bu->flags & BEE_USER_AWAY) != (old->flags & BEE_USER_AWAY) || 157 (bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE) || 158 (g_strcmp0(bu->status, old->status) != 0) || 159 (g_strcmp0(bu->status_msg, old->status_msg) != 0))) { 160 irc_send_away_notify(iu); 161 } 155 162 156 163 return TRUE; … … 292 299 } 293 300 294 wrapped = word_wrap(msg, 425);301 wrapped = word_wrap(msg, IRC_WORD_WRAP); 295 302 irc_send_msg(src_iu, message_type, dst, wrapped, prefix); 296 303 g_free(wrapped); … … 342 349 } 343 350 344 static gboolean bee_irc_user_nick_update(irc_user_t *iu );351 static gboolean bee_irc_user_nick_update(irc_user_t *iu, gboolean offline_only); 345 352 346 353 static gboolean bee_irc_user_fullname(bee_t *bee, bee_user_t *bu) … … 370 377 } 371 378 372 bee_irc_user_nick_update(iu );379 bee_irc_user_nick_update(iu, TRUE); 373 380 374 381 return TRUE; … … 377 384 static gboolean bee_irc_user_nick_hint(bee_t *bee, bee_user_t *bu, const char *hint) 378 385 { 379 bee_irc_user_nick_update((irc_user_t *) bu->ui_data); 386 bee_irc_user_nick_update((irc_user_t *) bu->ui_data, TRUE); 387 388 return TRUE; 389 } 390 391 static gboolean bee_irc_user_nick_change(bee_t *bee, bee_user_t *bu, const char *nick) 392 { 393 bee_irc_user_nick_update((irc_user_t *) bu->ui_data, FALSE); 380 394 381 395 return TRUE; … … 386 400 irc_user_t *iu = (irc_user_t *) bu->ui_data; 387 401 irc_t *irc = (irc_t *) bee->ui_data; 388 bee_user_flags_t online;389 390 /* Take the user offline temporarily so we can change the nick (if necessary). */391 if ((online = bu->flags & BEE_USER_ONLINE)) {392 bu->flags &= ~BEE_USER_ONLINE;393 }394 402 395 403 bee_irc_channel_update(irc, NULL, iu); 396 bee_irc_user_nick_update(iu); 397 398 if (online) { 399 bu->flags |= online; 400 bee_irc_channel_update(irc, NULL, iu); 401 } 402 403 return TRUE; 404 } 405 406 static gboolean bee_irc_user_nick_update(irc_user_t *iu) 404 bee_irc_user_nick_update(iu, FALSE); 405 406 return TRUE; 407 } 408 409 static gboolean bee_irc_user_nick_update(irc_user_t *iu, gboolean offline_only) 407 410 { 408 411 bee_user_t *bu = iu->bu; 409 412 char *newnick; 410 413 411 if ( bu->flags & BEE_USER_ONLINE) {414 if (offline_only && bu->flags & BEE_USER_ONLINE) { 412 415 /* Ignore if the user is visible already. */ 413 416 return TRUE; … … 432 435 { 433 436 bee_user_t *bu = iu->bu; 434 bee_user_flags_t online;435 437 436 438 if (bu == FALSE) { … … 438 440 } 439 441 440 /* In this case, pretend the user is offline. */441 if ((online = bu->flags & BEE_USER_ONLINE)) {442 bu->flags &= ~BEE_USER_ONLINE;443 }444 445 442 nick_del(bu); 446 bee_irc_user_nick_update(iu); 447 448 bu->flags |= online; 443 bee_irc_user_nick_update(iu, FALSE); 444 449 445 } 450 446 … … 461 457 } 462 458 463 if ((away = irc_user_get_away(iu)) && 459 if (iu->last_channel == NULL && 460 (away = irc_user_get_away(iu)) && 464 461 time(NULL) >= iu->away_reply_timeout) { 465 462 irc_send_num(iu->irc, 301, "%s :%s", iu->nick, away); … … 676 673 } 677 674 678 wrapped = word_wrap(msg, 425);675 wrapped = word_wrap(msg, IRC_WORD_WRAP); 679 676 irc_send_msg(iu, "PRIVMSG", ic->name, wrapped, ts); 680 677 g_free(ts); … … 1146 1143 1147 1144 bee_irc_log, 1145 bee_irc_user_nick_change, 1148 1146 }; -
irc_send.c
rba52ac5 r537d9b9 41 41 { 42 42 irc_send_num(irc, 1, ":Welcome to the %s gateway, %s", PACKAGE, irc->user->nick); 43 irc_send_num(irc, 2, ":Host %s is running %s %s %s/%s.", irc->root->host,44 PACKAGE, BITLBEE_VERSION , ARCH, CPU);43 irc_send_num(irc, 2, ":Host %s is running %s %s.", irc->root->host, 44 PACKAGE, BITLBEE_VERSION); 45 45 irc_send_num(irc, 3, ":%s", IRCD_INFO); 46 46 irc_send_num(irc, 4, "%s %s %s %s", irc->root->host, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES); … … 54 54 void irc_send_motd(irc_t *irc) 55 55 { 56 char motd[2048];57 s size_t len;58 int fd; 59 60 fd = open(global.conf->motdfile, O_RDONLY); 61 if ( fd == -1 || (len = read(fd, motd, sizeof(motd) - 1)) <= 0) {56 char *motd; 57 size_t len; 58 59 g_file_get_contents(global.conf->motdfile, &motd, &len, NULL); 60 61 if (!motd || !len) { 62 62 irc_send_num(irc, 422, ":We don't need MOTDs."); 63 63 } else { … … 66 66 67 67 in = motd; 68 motd[len] = '\0';69 68 linebuf[79] = len = 0; 70 69 max = sizeof(linebuf) - 1; … … 101 100 } 102 101 103 if (fd != -1) { 104 close(fd); 105 } 102 g_free(motd); 103 106 104 } 107 105 … … 348 346 } 349 347 350 /* rfc1459 doesn't mention this: G means gone, H means here */ 351 status_prefix[0] = iu->flags & IRC_USER_AWAY ? 'G' : 'H'; 348 /* If this is the account nick, check configuration to see if away */ 349 if (iu == irc->user) { 350 /* rfc1459 doesn't mention this: G means gone, H means here */ 351 status_prefix[0] = set_getstr(&irc->b->set, "away") ? 'G' : 'H'; 352 } else { 353 status_prefix[0] = iu->flags & IRC_USER_AWAY ? 'G' : 'H'; 354 } 352 355 353 356 irc_send_num(irc, 352, "%s %s %s %s %s %s :0 %s", -
irc_user.c
rba52ac5 r537d9b9 251 251 if (g_strcasecmp(ctcp[0], "VERSION") == 0) { 252 252 irc_send_msg_f(iu, "NOTICE", iu->irc->user->nick, "\001%s %s\001", 253 ctcp[0], PACKAGE " " BITLBEE_VERSION " " ARCH "/" CPU);253 ctcp[0], PACKAGE " " BITLBEE_VERSION); 254 254 } else if (g_strcasecmp(ctcp[0], "PING") == 0) { 255 255 irc_send_msg_f(iu, "NOTICE", iu->irc->user->nick, "\001%s %s\001", -
lib/http_client.c
rba52ac5 r537d9b9 95 95 request = g_strdup_printf("GET %s HTTP/1.0\r\n" 96 96 "Host: %s\r\n" 97 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n"97 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" 98 98 "\r\n", url->file, url->host); 99 99 -
lib/misc.c
rba52ac5 r537d9b9 549 549 } 550 550 551 /* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */552 551 char *word_wrap(const char *msg, int line_len) 553 552 { … … 582 581 } 583 582 if (i == 0) { 584 g_string_append_len(ret, msg, line_len); 583 const char *end; 584 size_t len; 585 586 g_utf8_validate(msg, line_len, &end); 587 588 len = (end != msg) ? end - msg : line_len; 589 590 g_string_append_len(ret, msg, len); 585 591 g_string_append_c(ret, '\n'); 586 msg += l ine_len;592 msg += len; 587 593 } 588 594 } … … 787 793 return string; 788 794 } 795 796 /* Returns a string that is exactly 'char_len' utf8 characters long (not bytes), 797 * padded to the right with spaces or truncated with the 'ellipsis' parameter 798 * if specified (can be NULL). 799 * Returns a newly allocated string, or NULL on invalid parameters. */ 800 char *str_pad_and_truncate(const char *string, long char_len, const char *ellipsis) 801 { 802 size_t string_len = strlen(string); 803 size_t ellipsis_len = (ellipsis) ? strlen(ellipsis) : 0; 804 long orig_len = g_utf8_strlen(string, -1); 805 806 g_return_val_if_fail(char_len > ellipsis_len, NULL); 807 808 if (orig_len > char_len) { 809 char *ret = g_malloc(string_len + 1); 810 g_utf8_strncpy(ret, string, char_len - ellipsis_len); 811 if (ellipsis) { 812 g_strlcat(ret, ellipsis, string_len); 813 } 814 return ret; 815 } else if (orig_len < char_len) { 816 return g_strdup_printf("%s%*s", string, (int) (char_len - orig_len), ""); 817 } else { 818 return g_strdup(string); 819 } 820 } -
lib/misc.h
rba52ac5 r537d9b9 151 151 G_MODULE_EXPORT gboolean parse_int64(char *string, int base, guint64 *number); 152 152 G_MODULE_EXPORT char *str_reject_chars(char *string, const char *reject, char replacement); 153 G_MODULE_EXPORT char *str_pad_and_truncate(const char *string, long char_len, const char *ellipsis); 153 154 154 155 #endif -
lib/proxy.c
rba52ac5 r537d9b9 87 87 } 88 88 89 /* calls phb->func safely by ensuring that the phb struct doesn't exist in the 90 * case that proxy_disconnect() is called down there */ 91 static gboolean phb_connected(struct PHB *phb, gint source) 92 { 93 /* save func and data here */ 94 b_event_handler func = phb->func; 95 gpointer data = phb->data; 96 97 /* free the struct so that it can't be freed by the callback */ 98 phb_free(phb, TRUE); 99 100 /* if any proxy_disconnect() call happens here, it will use the 101 * fd (still open), look it up in the hash table, get NULL, and 102 * proceed to close the fd and do nothing else */ 103 func(data, source, B_EV_IO_READ); 104 105 return FALSE; 106 } 107 89 108 static gboolean proxy_connected(gpointer data, gint source, b_input_condition cond) 90 109 { … … 125 144 phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ); 126 145 } else { 127 phb->func(phb->data, source, B_EV_IO_READ); 128 phb_free(phb, TRUE); 146 phb_connected(phb, source); 129 147 } 130 148 … … 222 240 if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || 223 241 (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { 224 phb->func(phb->data, source, B_EV_IO_READ); 225 return phb_free(phb, TRUE); 242 return phb_connected(phb, source); 226 243 } 227 244 … … 295 312 memset(packet, 0, sizeof(packet)); 296 313 if (read(source, packet, 9) >= 4 && packet[1] == 90) { 297 phb->func(phb->data, source, B_EV_IO_READ); 298 return phb_free(phb, TRUE); 314 return phb_connected(phb, source); 299 315 } 300 316 … … 384 400 } 385 401 386 phb->func(phb->data, source, B_EV_IO_READ); 387 return phb_free(phb, TRUE); 402 return phb_connected(phb, source); 388 403 } 389 404 -
lib/sha1.c
rba52ac5 r537d9b9 24 24 #define HMAC_BLOCK_SIZE 64 25 25 26 /* BitlBee addition: */ 27 void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, guint8 digest[SHA1_HASH_SIZE])26 void b_hmac(GChecksumType checksum_type, const char *key_, size_t key_len, 27 const char *payload, size_t payload_len, guint8 **digest) 28 28 { 29 sha1_state_t sha1; 30 guint8 hash[SHA1_HASH_SIZE]; 29 GChecksum *checksum; 30 size_t hash_len; 31 guint8 *hash; 31 32 guint8 key[HMAC_BLOCK_SIZE + 1]; 32 33 int i; 34 35 hash_len = g_checksum_type_get_length(checksum_type); 36 37 if (hash_len == (size_t) -1) { 38 return; 39 } 40 41 hash = g_malloc(hash_len); 33 42 34 43 if (key_len == 0) { … … 43 52 memset(key, 0, HMAC_BLOCK_SIZE + 1); 44 53 if (key_len > HMAC_BLOCK_SIZE) { 45 sha1_init(&sha1); 46 sha1_append(&sha1, (guint8 *) key_, key_len); 47 sha1_finish(&sha1, key); 54 checksum = g_checksum_new(checksum_type); 55 g_checksum_update(checksum, (guint8 *) key_, key_len); 56 g_checksum_get_digest(checksum, key, &hash_len); 57 g_checksum_free(checksum); 48 58 } else { 49 59 memcpy(key, key_, key_len); … … 51 61 52 62 /* Inner part: H(K XOR 0x36, text) */ 53 sha1_init(&sha1);63 checksum = g_checksum_new(checksum_type); 54 64 for (i = 0; i < HMAC_BLOCK_SIZE; i++) { 55 65 key[i] ^= 0x36; 56 66 } 57 sha1_append(&sha1, key, HMAC_BLOCK_SIZE); 58 sha1_append(&sha1, (const guint8 *) payload, payload_len); 59 sha1_finish(&sha1, hash); 67 g_checksum_update(checksum, key, HMAC_BLOCK_SIZE); 68 g_checksum_update(checksum, (const guint8 *) payload, payload_len); 69 g_checksum_get_digest(checksum, hash, &hash_len); 70 g_checksum_free(checksum); 60 71 61 72 /* Final result: H(K XOR 0x5C, inner stuff) */ 62 sha1_init(&sha1);73 checksum = g_checksum_new(checksum_type); 63 74 for (i = 0; i < HMAC_BLOCK_SIZE; i++) { 64 75 key[i] ^= 0x36 ^ 0x5c; 65 76 } 66 sha1_append(&sha1, key, HMAC_BLOCK_SIZE); 67 sha1_append(&sha1, hash, SHA1_HASH_SIZE); 68 sha1_finish(&sha1, digest); 77 g_checksum_update(checksum, key, HMAC_BLOCK_SIZE); 78 g_checksum_update(checksum, hash, hash_len); 79 g_checksum_get_digest(checksum, *digest, &hash_len); 80 g_checksum_free(checksum); 81 82 g_free(hash); 69 83 } 84 85 void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, guint8 digest[SHA1_HASH_SIZE]) 86 { 87 b_hmac(G_CHECKSUM_SHA1, key_, key_len, payload, payload_len, &digest); 88 } 89 70 90 71 91 /* I think this follows the scheme described on: -
lib/ssl_gnutls.c
rba52ac5 r537d9b9 42 42 #include <limits.h> 43 43 44 #if defined(ULONG_MAX) && ULONG_MAX > 4294967295UL45 #define GNUTLS_STUPID_CAST (long)46 #else47 #define GNUTLS_STUPID_CAST (int)48 #endif49 50 44 #define SSLDEBUG 0 51 45 … … 335 329 336 330 sock_make_nonblocking(conn->fd); 337 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) GNUTLS_STUPID_CASTconn->fd);331 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) (long) conn->fd); 338 332 339 333 ssl_cache_resume(conn); -
lib/ssl_openssl.c
rba52ac5 r537d9b9 67 67 SSL_library_init(); 68 68 69 meth = TLSv1_client_method();69 meth = SSLv23_client_method(); 70 70 ssl_ctx = SSL_CTX_new(meth); 71 SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); 71 72 72 73 initialized = TRUE; -
otr.c
rba52ac5 r537d9b9 268 268 } 269 269 270 #ifndef OTR_BI 271 struct plugin_info *init_plugin_info(void) 272 { 273 static struct plugin_info info = { 274 BITLBEE_ABI_VERSION_CODE, 275 "otr", 276 BITLBEE_VERSION, 277 "Off-the-Record communication", 278 NULL, 279 NULL 280 }; 281 282 return &info; 283 } 284 #endif 285 270 286 gboolean otr_irc_new(irc_t *irc) 271 287 { … … 413 429 414 430 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ 415 if (a->prpl->options & OPT_NOOTR) {431 if (a->prpl->options & PRPL_OPT_NOOTR) { 416 432 return 0; 417 433 } … … 441 457 442 458 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ 443 if (ic->acc->prpl->options & OPT_NOOTR ||459 if (ic->acc->prpl->options & PRPL_OPT_NOOTR || 444 460 iu->bu->flags & BEE_USER_NOOTR) { 445 461 return msg; … … 1384 1400 void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...) 1385 1401 { 1402 char *msg_, *msg; 1386 1403 struct im_connection *ic = 1387 1404 check_imc(opdata, ctx->accountname, ctx->protocol); … … 1391 1408 1392 1409 va_start(va, fmt); 1393 char *msg= g_strdup_vprintf(fmt, va);1410 msg_ = g_strdup_vprintf(fmt, va); 1394 1411 va_end(va); 1412 1413 msg = word_wrap(msg_, IRC_WORD_WRAP); 1395 1414 1396 1415 if (u) { … … 1401 1420 } 1402 1421 1422 g_free(msg_); 1403 1423 g_free(msg); 1404 1424 } -
protocols/account.c
rba52ac5 r537d9b9 63 63 64 64 s = set_add(&a->set, "password", NULL, set_eval_account, a); 65 s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD ;65 s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD | ACC_SET_LOCKABLE; 66 66 67 67 s = set_add(&a->set, "tag", NULL, set_eval_account, a); … … 69 69 70 70 s = set_add(&a->set, "username", NULL, set_eval_account, a); 71 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY ;71 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | ACC_SET_LOCKABLE; 72 72 set_setstr(&a->set, "username", user); 73 73 -
protocols/account.h
rba52ac5 r537d9b9 61 61 ACC_SET_OFFLINE_ONLY = 0x02, /* Allow changes only if the acct is offline. */ 62 62 ACC_SET_ONLINE_ONLY = 0x04, /* Allow changes only if the acct is online. */ 63 ACC_SET_LOCKABLE = 0x08 /* Setting cannot be changed if the account is locked down */ 63 64 } account_set_flag_t; 64 65 … … 68 69 ACC_FLAG_HANDLE_DOMAINS = 0x04, /* Contact handles need a domain portion. */ 69 70 ACC_FLAG_LOCAL_CONTACTS = 0x08, /* Contact list is local. */ 71 ACC_FLAG_LOCKED = 0x10, /* Account is locked (cannot be deleted, certain settings can't changed) */ 70 72 } account_flag_t; 71 73 -
protocols/bee.h
rba52ac5 r537d9b9 84 84 } bee_user_t; 85 85 86 typedef struct bee_chat_info { 87 char *title; 88 char *topic; 89 } bee_chat_info_t; 90 86 91 /* This one's mostly used so save space and make it easier (cheaper) to 87 92 compare groups of contacts, etc. */ … … 131 136 132 137 void (*log)(bee_t *bee, const char *tag, const char *msg); 138 gboolean (*user_nick_change)(bee_t *bee, bee_user_t *bu, const char *hint); 133 139 } bee_ui_funcs_t; 134 140 … … 184 190 G_MODULE_EXPORT void imcb_chat_invite(struct im_connection *ic, const char *name, const char *who, const char *msg); 185 191 192 G_GNUC_DEPRECATED G_MODULE_EXPORT void bee_chat_list_finish(struct im_connection *ic); 193 G_MODULE_EXPORT void imcb_chat_list_finish(struct im_connection *ic); 194 G_MODULE_EXPORT void imcb_chat_list_free(struct im_connection *ic); 195 186 196 #endif /* __BEE_H__ */ -
protocols/bee_chat.c
rba52ac5 r537d9b9 274 274 } 275 275 } 276 277 void imcb_chat_list_finish(struct im_connection *ic) 278 { 279 cmd_chat_list_finish(ic); 280 } 281 282 void bee_chat_list_finish(struct im_connection *ic) 283 { 284 imcb_log(ic, "Warning: using deprecated bee_chat_list_finish. This will be removed in the stable release."); 285 imcb_chat_list_finish(ic); 286 } 287 288 void imcb_chat_list_free(struct im_connection *ic) 289 { 290 bee_chat_info_t *ci; 291 GSList *l = ic->chatlist; 292 293 while (l) { 294 ci = l->data; 295 l = g_slist_delete_link(l, l); 296 297 g_free(ci->title); 298 g_free(ci->topic); 299 g_free(ci); 300 } 301 302 ic->chatlist = NULL; 303 } -
protocols/bee_ft.c
rba52ac5 r537d9b9 31 31 bee_user_t *bu = bee_user_by_handle(bee, ic, handle); 32 32 33 if (bee->ui->ft_in_start ) {33 if (bee->ui->ft_in_start && bu) { 34 34 return bee->ui->ft_in_start(bee, bu, file_name, file_size); 35 35 } else { -
protocols/jabber/conference.c
rba52ac5 r537d9b9 28 28 static xt_status jabber_chat_self_message(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 29 29 30 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password) 30 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password, 31 gboolean always_use_nicks) 31 32 { 32 33 struct jabber_chat *jc; … … 57 58 g_free(jc); 58 59 return NULL; 60 } 61 62 if (always_use_nicks) { 63 jc->flags = JCFLAG_ALWAYS_USE_NICKS; 59 64 } 60 65 … … 95 100 g_free(cserv); 96 101 97 c = jabber_chat_join(ic, rjid, jd->username, NULL );102 c = jabber_chat_join(ic, rjid, jd->username, NULL, FALSE); 98 103 g_free(rjid); 99 104 if (c == NULL) { … … 244 249 } 245 250 251 static int jabber_chat_has_other_resources(struct im_connection *ic, struct jabber_buddy *bud) 252 { 253 struct jabber_buddy *cur; 254 255 for (cur = jabber_buddy_by_jid(ic, bud->bare_jid, GET_BUDDY_FIRST); cur; cur = cur->next) { 256 if (cur != bud && jabber_compare_jid(cur->ext_jid, bud->ext_jid)) { 257 return TRUE; 258 } 259 } 260 261 return FALSE; 262 } 263 246 264 /* Not really the same syntax as the normal pkt_ functions, but this isn't 247 265 called by the xmltree parser directly and this way I can add some extra … … 328 346 *s = 0; /* Should NEVER be NULL, but who knows... */ 329 347 } 348 349 if (bud != jc->me && (jc->flags & JCFLAG_ALWAYS_USE_NICKS) && !(bud->flags & JBFLAG_IS_ANONYMOUS)) { 350 imcb_buddy_nick_change(ic, bud->ext_jid, bud->resource); 351 } 352 330 353 imcb_chat_add_buddy(chat, bud->ext_jid); 331 354 if (s) { … … 333 356 } 334 357 } else if (type) { /* type can only be NULL or "unavailable" in this function */ 335 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid ) {358 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid && !jabber_chat_has_other_resources(ic, bud)) { 336 359 char *reason = NULL; 337 360 char *status = NULL; … … 443 466 444 467 if (subject && chat) { 445 char *subject_text = subject->text_len > 0 ? subject->text : ""; 468 char empty[1] = ""; 469 char *subject_text = subject->text_len > 0 ? subject->text : empty; 446 470 if (g_strcmp0(chat->topic, subject_text) != 0) { 447 471 bare_jid = (bud) ? jabber_get_bare_jid(bud->ext_jid) : NULL; … … 479 503 bare_jid = jabber_get_bare_jid(bud->ext_jid ? bud->ext_jid : bud->full_jid); 480 504 final_from = bare_jid; 481 flags = (bud == jc->me) ? OPT_SELFMESSAGE : 0; 505 if (bud == jc->me || (g_strcasecmp(final_from, ic->acc->user) == 0)) { 506 flags = OPT_SELFMESSAGE; 507 } 482 508 } else { 483 509 final_from = nick; -
protocols/jabber/iq.c
rba52ac5 r537d9b9 67 67 xt_add_child(reply, xt_new_node("name", set_getstr(&ic->acc->set, "user_agent"), NULL)); 68 68 xt_add_child(reply, xt_new_node("version", BITLBEE_VERSION, NULL)); 69 xt_add_child(reply, xt_new_node("os", ARCH, NULL));70 69 } else if (strcmp(s, XMLNS_TIME_OLD) == 0) { 71 70 time_t time_ep; … … 234 233 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 235 234 imc_logout(ic, FALSE); 236 return XT_ HANDLED;235 return XT_ABORT; 237 236 } 238 237 … … 287 286 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 288 287 imc_logout(ic, FALSE); 289 return XT_ HANDLED;288 return XT_ABORT; 290 289 } 291 290 … … 1060 1059 return XT_HANDLED; 1061 1060 } 1061 1062 xt_status jabber_iq_disco_muc_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 1063 1064 int jabber_iq_disco_muc(struct im_connection *ic, const char *muc_server) 1065 { 1066 struct xt_node *node; 1067 int st; 1068 1069 node = xt_new_node("query", NULL, NULL); 1070 xt_add_attr(node, "xmlns", XMLNS_DISCO_ITEMS); 1071 node = jabber_make_packet("iq", "get", (char *) muc_server, node); 1072 1073 jabber_cache_add(ic, node, jabber_iq_disco_muc_response); 1074 st = jabber_write_packet(ic, node); 1075 1076 return st; 1077 } 1078 1079 xt_status jabber_iq_disco_muc_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 1080 { 1081 struct xt_node *query, *c; 1082 struct jabber_error *err; 1083 GSList *rooms = NULL; 1084 1085 if ((err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR))) { 1086 imcb_error(ic, "The server replied with an error: %s%s%s", 1087 err->code, err->text ? ": " : "", err->text ? err->text : ""); 1088 jabber_error_free(err); 1089 return XT_HANDLED; 1090 } 1091 1092 if (!(query = xt_find_node(node->children, "query"))) { 1093 imcb_error(ic, "Received incomplete MUC list reply"); 1094 return XT_HANDLED; 1095 } 1096 1097 c = query->children; 1098 while ((c = xt_find_node(c, "item"))) { 1099 char *jid = xt_find_attr(c, "jid"); 1100 1101 if (!jid || !strchr(jid, '@')) { 1102 c = c->next; 1103 continue; 1104 } 1105 1106 bee_chat_info_t *ci = g_new(bee_chat_info_t, 1); 1107 ci->title = g_strdup(xt_find_attr(c, "jid")); 1108 ci->topic = g_strdup(xt_find_attr(c, "name")); 1109 rooms = g_slist_prepend(rooms, ci); 1110 1111 c = c->next; 1112 } 1113 1114 imcb_chat_list_free(ic); 1115 ic->chatlist = g_slist_reverse(rooms); 1116 imcb_chat_list_finish(ic); 1117 1118 return XT_HANDLED; 1119 } -
protocols/jabber/jabber.c
rba52ac5 r537d9b9 82 82 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; 83 83 84 set_add(&acc->set, "oauth", "false", set_eval_oauth, acc); 85 84 86 if (strcmp(acc->prpl->name, "hipchat") == 0) { 85 87 set_setstr(&acc->set, "server", "chat.hipchat.com"); 86 88 } else { 87 set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);88 89 89 /* this reuses set_eval_oauth, which clears the password */ 90 90 set_add(&acc->set, "anonymous", "false", set_eval_oauth, acc); … … 321 321 struct jabber_data *jd = ic->proto_data; 322 322 323 imcb_chat_list_free(ic); 324 323 325 while (jd->filetransfers) { 324 326 imcb_file_canceled(ic, (( struct jabber_transfer *) jd->filetransfers->data)->ft, "Logging out"); … … 397 399 if (g_strcasecmp(who, JABBER_OAUTH_HANDLE) == 0 && 398 400 !(jd->flags & OPT_LOGGED_IN) && jd->fd == -1) { 399 if (sasl_oauth2_get_refresh_token(ic, message)) { 401 402 if (jd->flags & JFLAG_HIPCHAT) { 403 sasl_oauth2_got_token(ic, message, NULL, NULL); 404 return 1; 405 } else if (sasl_oauth2_get_refresh_token(ic, message)) { 400 406 return 1; 401 407 } else { … … 577 583 } else { 578 584 /* jabber_chat_join without the underscore is the conference.c one */ 579 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password")); 585 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password"), 586 set_getbool(sets, "always_use_nicks")); 580 587 } 581 588 … … 586 593 { 587 594 return jabber_chat_with(ic, who); 595 } 596 597 static void jabber_chat_list_(struct im_connection *ic, const char *server) 598 { 599 struct jabber_data *jd = ic->proto_data; 600 601 if (server && *server) { 602 jabber_iq_disco_muc(ic, server); 603 } else if (jd->muc_host && *jd->muc_host) { 604 jabber_iq_disco_muc(ic, jd->muc_host); 605 } else { 606 /* throw an error here, don't query conference.[server] directly. 607 * for things like jabber.org it gets you 18000 results of garbage */ 608 imcb_error(ic, "Please specify a server name such as `conference.%s'", jd->server); 609 } 588 610 } 589 611 … … 686 708 void jabber_chat_add_settings(account_t *acc, set_t **head) 687 709 { 710 set_add(head, "always_use_nicks", "false", set_eval_bool, NULL); 711 688 712 /* Meh. Stupid room passwords. Not trying to obfuscate/hide 689 713 them from the user for now. */ … … 693 717 void jabber_chat_free_settings(account_t *acc, set_t **head) 694 718 { 719 set_del(head, "always_use_nicks"); 720 695 721 set_del(head, "password"); 696 722 } … … 759 785 ret->chat_join = jabber_chat_join_; 760 786 ret->chat_with = jabber_chat_with_; 787 ret->chat_list = jabber_chat_list_; 761 788 ret->chat_add_settings = jabber_chat_add_settings; 762 789 ret->chat_free_settings = jabber_chat_free_settings; -
protocols/jabber/jabber.h
rba52ac5 r537d9b9 75 75 JCFLAG_MESSAGE_SENT = 1, /* Set this after sending the first message, so 76 76 we can detect echoes/backlogs. */ 77 JCFLAG_ALWAYS_USE_NICKS = 2, 77 78 } jabber_chat_flags_t; 78 79 … … 262 263 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data); 263 264 int jabber_iq_disco_server(struct im_connection *ic); 265 int jabber_iq_disco_muc(struct im_connection *ic, const char *muc_server); 264 266 265 267 /* si.c */ … … 339 341 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg); 340 342 int sasl_oauth2_refresh(struct im_connection *ic, const char *refresh_token); 343 void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error); 341 344 342 345 extern const struct oauth2_service oauth2_service_google; 343 346 344 347 /* conference.c */ 345 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password); 348 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password, 349 gboolean always_use_nicks); 346 350 struct groupchat *jabber_chat_with(struct im_connection *ic, char *who); 347 351 struct groupchat *jabber_chat_by_jid(struct im_connection *ic, const char *name); -
protocols/jabber/jabber_util.c
rba52ac5 r537d9b9 315 315 int i; 316 316 317 if (!jid1 || !jid2) { 318 return FALSE; 319 } 320 317 321 for (i = 0;; i++) { 318 322 if (jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/') { -
protocols/jabber/message.c
rba52ac5 r537d9b9 27 27 { 28 28 struct im_connection *ic = data; 29 struct jabber_data *jd = ic->proto_data;30 29 char *from = xt_find_attr(node, carbons_sent ? "to" : "from"); 31 30 char *type = xt_find_attr(node, "type"); … … 38 37 if (!from) { 39 38 return XT_HANDLED; /* Consider this packet corrupted. */ 40 }41 42 /* try to detect hipchat's own version of self-messages */43 if (jd->flags & JFLAG_HIPCHAT) {44 struct xt_node *c;45 46 if ((c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY)) &&47 (s = xt_find_attr(c, "from_jid")) &&48 jabber_compare_jid(s, jd->me)) {49 carbons_sent = TRUE;50 }51 39 } 52 40 -
protocols/jabber/presence.c
rba52ac5 r537d9b9 222 222 cap = xt_new_node("c", NULL, NULL); 223 223 xt_add_attr(cap, "xmlns", XMLNS_CAPS); 224 225 if (jd->flags & JFLAG_HIPCHAT) { 226 /* hipchat specific node, whitelisted by request to receive self-messages */ 227 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps/hipchat"); 228 } else { 229 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps"); 230 } 224 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps"); 231 225 xt_add_attr(cap, "ver", BITLBEE_VERSION); /* The XEP wants this hashed, but nobody's doing that. */ 232 226 xt_add_child(node, cap); -
protocols/jabber/s5bytestream.c
rba52ac5 r537d9b9 928 928 proxy = next; 929 929 } 930 931 g_free(proxysetting); 930 932 } 931 933 -
protocols/jabber/sasl.c
rba52ac5 r537d9b9 39 39 }; 40 40 41 /* """"""""""""""""""""""""""""""oauth"""""""""""""""""""""""""""""" */ 42 #define HIPCHAT_SO_CALLED_OAUTH_URL "https://hipchat.com/account/api" 43 41 44 xt_status sasl_pkt_mechanisms(struct xt_node *node, gpointer data) 42 45 { … … 45 48 struct xt_node *c, *reply; 46 49 char *s; 47 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_anonymous = 0 ;50 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_anonymous = 0, sup_hipchat_oauth = 0; 48 51 int want_oauth = FALSE, want_hipchat = FALSE, want_anonymous = FALSE; 49 52 GString *mechs; … … 80 83 } else if (c->text && g_strcasecmp(c->text, "X-OAUTH2") == 0) { 81 84 sup_gtalk = 1; 85 } else if (c->text && g_strcasecmp(c->text, "X-HIPCHAT-OAUTH2") == 0) { 86 sup_hipchat_oauth = 1; 82 87 } 83 88 … … 90 95 91 96 if (!want_oauth && !sup_plain && !sup_digest) { 92 if ( !sup_gtalk) {97 if (sup_gtalk || sup_hipchat_oauth) { 93 98 imcb_error(ic, "This server requires OAuth " 94 99 "(supported schemes:%s)", mechs->str); … … 110 115 } 111 116 112 if (sup_gtalk && want_oauth) { 113 int len; 114 115 /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. 116 It's currently used by GTalk and vaguely documented on 117 http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ 118 xt_add_attr(reply, "mechanism", "X-OAUTH2"); 119 120 len = strlen(jd->username) + strlen(jd->oauth2_access_token) + 2; 121 s = g_malloc(len + 1); 122 s[0] = 0; 123 strcpy(s + 1, jd->username); 124 strcpy(s + 2 + strlen(jd->username), jd->oauth2_access_token); 125 reply->text = base64_encode((unsigned char *) s, len); 117 if ((sup_gtalk || sup_hipchat_oauth) && want_oauth) { 118 GString *gs; 119 120 gs = g_string_sized_new(128); 121 122 g_string_append_c(gs, '\0'); 123 124 if (sup_gtalk) { 125 /* X-OAUTH2 is not *the* standard OAuth2 SASL/XMPP implementation. 126 It's currently used by GTalk and vaguely documented on 127 http://code.google.com/apis/cloudprint/docs/rawxmpp.html */ 128 xt_add_attr(reply, "mechanism", "X-OAUTH2"); 129 130 g_string_append(gs, jd->username); 131 g_string_append_c(gs, '\0'); 132 g_string_append(gs, jd->oauth2_access_token); 133 } else if (sup_hipchat_oauth) { 134 /* Hipchat's variant, not standard either, is documented here: 135 https://docs.atlassian.com/hipchat.xmpp/latest/xmpp/auth.html */ 136 xt_add_attr(reply, "mechanism", "oauth2"); 137 138 g_string_append(gs, jd->oauth2_access_token); 139 g_string_append_c(gs, '\0'); 140 g_string_append(gs, set_getstr(&ic->acc->set, "resource")); 141 } 142 143 reply->text = base64_encode((unsigned char *) gs->str, gs->len); 126 144 reply->text_len = strlen(reply->text); 127 g_free(s); 145 g_string_free(gs, TRUE); 146 128 147 } else if (want_oauth) { 129 148 imcb_error(ic, "OAuth requested, but not supported by server"); … … 149 168 /* The rest will be done later, when we receive a <challenge/>. */ 150 169 } else if (sup_plain) { 151 int len;152 170 GString *gs; 153 171 char *username; … … 174 192 } 175 193 176 len = gs->len; 177 s = g_string_free(gs, FALSE); 178 179 reply->text = base64_encode((unsigned char *) s, len); 194 reply->text = base64_encode((unsigned char *) gs->str, gs->len); 180 195 reply->text_len = strlen(reply->text); 181 g_ free(s);196 g_string_free(gs, TRUE); 182 197 } 183 198 … … 428 443 { 429 444 struct jabber_data *jd = ic->proto_data; 430 char *msg, *url;431 445 432 446 imcb_log(ic, "Starting OAuth authentication"); … … 434 448 /* Temporary contact, just used to receive the OAuth response. */ 435 449 imcb_add_buddy(ic, JABBER_OAUTH_HANDLE, NULL); 436 url = oauth2_url(jd->oauth2_service); 437 msg = g_strdup_printf("Open this URL in your browser to authenticate: %s", url); 438 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, msg, 0, 0); 450 451 if (jd->flags & JFLAG_HIPCHAT) { 452 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, 453 "Open this URL and generate a token with 'View Group' and 'Send Message' scopes: " 454 HIPCHAT_SO_CALLED_OAUTH_URL, 0, 0); 455 } else { 456 char *msg, *url; 457 458 url = oauth2_url(jd->oauth2_service); 459 msg = g_strdup_printf("Open this URL in your browser to authenticate: %s", url); 460 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, msg, 0, 0); 461 462 g_free(msg); 463 g_free(url); 464 } 439 465 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, "Respond to this message with the returned " 440 466 "authorization token.", 0, 0); 441 467 442 g_free(msg);443 g_free(url);444 468 } 445 469 … … 453 477 return FALSE; 454 478 } 455 456 static void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token,457 const char *error);458 479 459 480 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg) … … 486 507 } 487 508 488 staticvoid sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error)509 void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error) 489 510 { 490 511 struct im_connection *ic = data; -
protocols/jabber/si.c
rba52ac5 r537d9b9 393 393 struct jabber_transfer *tf = NULL; 394 394 struct jabber_data *jd = ic->proto_data; 395 struct jabber_error *err; 395 396 396 397 if (!(tgt_jid = xt_find_attr(node, "from")) || 397 !(ini_jid = xt_find_attr(node, "to"))) { 398 !(ini_jid = xt_find_attr(node, "to")) || 399 !(iq_id = xt_find_attr(node, "id"))) { 398 400 imcb_log(ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid); 401 return XT_HANDLED; 402 } 403 404 /* Let's see if we can find out what this bytestream should be for... */ 405 406 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 407 struct jabber_transfer *tft = tflist->data; 408 if ((strcmp(tft->iq_id, iq_id) == 0)) { 409 tf = tft; 410 break; 411 } 412 } 413 414 if (!tf) { 415 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid); 416 return XT_HANDLED; 417 } 418 419 err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR); 420 421 if (err) { 422 if (g_strcmp0(err->code, "forbidden") == 0) { 423 imcb_log(ic, "File %s: %s rejected the transfer", tf->ft->file_name, tgt_jid); 424 } else { 425 imcb_log(ic, "Error: Stream initiation request failed: %s (%s)", err->code, err->text); 426 } 427 imcb_file_canceled(ic, tf->ft, "Stream initiation request failed"); 428 jabber_error_free(err); 399 429 return XT_HANDLED; 400 430 } … … 409 439 * <value> 410 440 */ 411 if (!(tgt_jid = xt_find_attr(node, "from")) || 412 !(ini_jid = xt_find_attr(node, "to")) || 413 !(iq_id = xt_find_attr(node, "id")) || 414 !(c = xt_find_node(node->children, "si")) || 441 if (!(c = xt_find_node(node->children, "si")) || 415 442 !(cmp = xt_find_attr(c, "xmlns")) || 416 443 !(strcmp(cmp, XMLNS_SI) == 0) || … … 439 466 } 440 467 441 /* Let's see if we can find out what this bytestream should be for... */442 443 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {444 struct jabber_transfer *tft = tflist->data;445 if ((strcmp(tft->iq_id, iq_id) == 0)) {446 tf = tft;447 break;448 }449 }450 451 if (!tf) {452 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);453 return XT_HANDLED;454 }455 456 468 tf->ini_jid = g_strdup(ini_jid); 457 469 tf->tgt_jid = g_strdup(tgt_jid); -
protocols/nogaim.c
rba52ac5 r537d9b9 40 40 41 41 #ifdef WITH_PLUGINS 42 GList *plugins = NULL; 43 44 static gint pluginscmp(gconstpointer a, gconstpointer b, gpointer data) 45 { 46 const struct plugin_info *ia = a; 47 const struct plugin_info *ib = b; 48 49 return g_strcasecmp(ia->name, ib->name); 50 } 51 42 52 gboolean load_plugin(char *path) 43 53 { 54 GList *l; 55 struct plugin_info *i; 56 struct plugin_info *info; 57 struct plugin_info * (*info_function) (void) = NULL; 44 58 void (*init_function) (void); 45 59 46 60 GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY); 61 gboolean loaded = FALSE; 47 62 48 63 if (!mod) { 49 log_message(LOGLVL_ERROR, " Can't find `%s', not loading (%s)\n", path, g_module_error());64 log_message(LOGLVL_ERROR, "Error loading plugin `%s': %s\n", path, g_module_error()); 50 65 return FALSE; 66 } 67 68 if (g_module_symbol(mod, "init_plugin_info", (gpointer *) &info_function)) { 69 info = info_function(); 70 71 if (info->abiver != BITLBEE_ABI_VERSION_CODE) { 72 log_message(LOGLVL_ERROR, 73 "`%s' uses ABI %u but %u is required\n", 74 path, info->abiver, 75 BITLBEE_ABI_VERSION_CODE); 76 g_module_close(mod); 77 return FALSE; 78 } 79 80 if (!info->name || !info->version) { 81 log_message(LOGLVL_ERROR, 82 "Name or version missing from the " 83 "plugin info in `%s'\n", path); 84 g_module_close(mod); 85 return FALSE; 86 } 87 88 for (l = plugins; l; l = l->next) { 89 i = l->data; 90 91 if (g_strcasecmp(i->name, info->name) == 0) { 92 loaded = TRUE; 93 break; 94 } 95 } 96 97 if (loaded) { 98 log_message(LOGLVL_WARNING, 99 "%s plugin already loaded\n", 100 info->name); 101 g_module_close(mod); 102 return FALSE; 103 } 104 } else { 105 log_message(LOGLVL_WARNING, "Can't find function `init_plugin_info' in `%s'\n", path); 51 106 } 52 107 53 108 if (!g_module_symbol(mod, "init_plugin", (gpointer *) &init_function)) { 54 109 log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path); 110 g_module_close(mod); 55 111 return FALSE; 56 112 } 57 113 114 if (info_function) { 115 plugins = g_list_insert_sorted_with_data(plugins, info, 116 pluginscmp, NULL); 117 } 118 58 119 init_function(); 59 60 120 return TRUE; 61 121 } … … 73 133 74 134 while ((entry = g_dir_read_name(dir))) { 135 if (!g_str_has_suffix(entry, "." G_MODULE_SUFFIX)) { 136 continue; 137 } 138 75 139 path = g_build_filename(global.conf->plugindir, entry, NULL); 76 140 if (!path) { … … 86 150 g_dir_close(dir); 87 151 } 152 } 153 154 GList *get_plugins() 155 { 156 return plugins; 88 157 } 89 158 #endif … … 168 237 load_plugins(); 169 238 #endif 239 } 240 241 GList *get_protocols() 242 { 243 return protocols; 244 } 245 246 GList *get_protocols_disabled() 247 { 248 return disabled_protocols; 170 249 } 171 250 … … 495 574 } 496 575 497 /* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM 498 modules to suggest a nickname for a handle. */ 499 void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick) 576 /* Implements either imcb_buddy_nick_hint() or imcb_buddy_nick_change() depending on the value of 'change' */ 577 static void buddy_nick_hint_or_change(struct im_connection *ic, const char *handle, const char *nick, gboolean change) 500 578 { 501 579 bee_t *bee = ic->bee; … … 509 587 bu->nick = g_strdup(nick); 510 588 511 if (bee->ui->user_nick_hint) { 589 if (change && bee->ui->user_nick_change) { 590 bee->ui->user_nick_change(bee, bu, nick); 591 } else if (!change && bee->ui->user_nick_hint) { 512 592 bee->ui->user_nick_hint(bee, bu, nick); 513 593 } 594 } 595 596 /* Soft variant, for newly created users. Does nothing if it's already online */ 597 void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick) 598 { 599 buddy_nick_hint_or_change(ic, handle, nick, FALSE); 600 } 601 602 /* Hard variant, always changes the nick */ 603 void imcb_buddy_nick_change(struct im_connection *ic, const char *handle, const char *nick) 604 { 605 buddy_nick_hint_or_change(ic, handle, nick, TRUE); 514 606 } 515 607 … … 667 759 if (away && *away) { 668 760 GList *m = ic->acc->prpl->away_states(ic); 761 if (m == NULL) { 762 return 0; 763 } 669 764 msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL; 670 765 away = imc_away_state_find(m, away, &msg) ? : -
protocols/nogaim.h
rba52ac5 r537d9b9 102 102 103 103 GSList *groupchats; 104 GSList *chatlist; 104 105 }; 105 106 … … 144 145 char *description; 145 146 }; 147 148 /* This enum takes a few things from libpurple and a few things from old OPT_ flags. 149 * The only flag that was used before this struct was PRPL_OPT_NOOTR. 150 * 151 * The libpurple ones only use the same values as the PurpleProtocolOptions 152 * enum for convenience, but there's no promise of direct compatibility with 153 * those values. As of libpurple 2.8.0 they use up to 0x800 (1 << 11), which is 154 * a nice coincidence. 155 */ 156 typedef enum { 157 /* The protocol doesn't use passwords 158 * Mirrors libpurple's OPT_PROTO_NO_PASSWORD */ 159 PRPL_OPT_NO_PASSWORD = 1 << 4, 160 161 /* The protocol doesn't require passwords, but may use them 162 * Mirrors libpurple's OPT_PROTO_PASSWORD_OPTIONAL */ 163 PRPL_OPT_PASSWORD_OPTIONAL = 1 << 7, 164 165 /* The protocol is not suitable for OTR, see OPT_NOOTR */ 166 PRPL_OPT_NOOTR = 1 << 12, 167 } prpl_options_t; 146 168 147 169 struct prpl { … … 269 291 gboolean (* handle_is_self) (struct im_connection *, const char *who); 270 292 293 /* This sets/updates the im_connection->chatlist field with a 294 * bee_chat_info_t GSList. This function should ensure the 295 * bee_chat_list_finish() function gets called at some point 296 * after the chat list is completely updated. 297 */ 298 void (* chat_list) (struct im_connection *, const char *server); 299 271 300 /* Some placeholders so eventually older plugins may cooperate with newer BitlBees. */ 272 301 void *resv1; … … 277 306 }; 278 307 308 struct plugin_info 309 { 310 guint abiver; 311 const char *name; 312 const char *version; 313 const char *description; 314 const char *author; 315 const char *url; 316 }; 317 318 #ifdef WITH_PLUGINS 319 G_MODULE_EXPORT GList *get_plugins(); 320 #endif 321 279 322 /* im_api core stuff. */ 280 323 void nogaim_init(); 324 G_MODULE_EXPORT GList *get_protocols(); 325 G_MODULE_EXPORT GList *get_protocols_disabled(); 281 326 G_MODULE_EXPORT GSList *get_connections(); 282 327 G_MODULE_EXPORT struct prpl *find_protocol(const char *name); … … 330 375 G_MODULE_EXPORT void imcb_rename_buddy(struct im_connection *ic, const char *handle, const char *realname); 331 376 G_MODULE_EXPORT void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick); 377 G_MODULE_EXPORT void imcb_buddy_nick_change(struct im_connection *ic, const char *handle, const char *nick); 332 378 G_MODULE_EXPORT void imcb_buddy_action_response(bee_user_t *bu, const char *action, char * const args[], void *data); 333 379 G_MODULE_EXPORT GSList *imcb_get_local_contacts(struct im_connection *ic); -
protocols/oscar/conn.c
rba52ac5 r537d9b9 383 383 { 384 384 aim_conn_t *connstruct; 385 guint16 port = AIM_LOGIN_PORT;386 char *host;387 int i;388 385 389 386 if (!(connstruct = aim_conn_getnext(sess))) { … … 400 397 } 401 398 402 /* 403 * As of 23 Jul 1999, AOL now sends the port number, preceded by a 404 * colon, in the BOS redirect. This fatally breaks all previous 405 * libfaims. Bad, bad AOL. 406 * 407 * We put this here to catch every case. 408 * 409 */ 410 411 for (i = 0; i < (int) strlen(dest); i++) { 412 if (dest[i] == ':') { 413 port = atoi(&(dest[i + 1])); 414 break; 415 } 416 } 417 418 host = (char *) g_malloc(i + 1); 419 strncpy(host, dest, i); 420 host[i] = '\0'; 421 422 connstruct->fd = proxy_connect(host, port, NULL, NULL); 423 424 g_free(host); 399 /* The code that used to be here was very broken */ 400 g_return_val_if_reached(connstruct); 425 401 426 402 return connstruct; -
protocols/purple/bpurple.h
rba52ac5 r537d9b9 13 13 GHashTable *input_requests; 14 14 guint next_request_id; 15 char *chat_list_server; 16 GSList *filetransfers; 15 17 }; 16 18 -
protocols/purple/ft.c
rba52ac5 r537d9b9 42 42 char *fn, *handle; 43 43 gboolean ui_wants_data; 44 int timeout; 44 45 }; 45 46 … … 64 65 struct prpl_xfer_data *px = ft->data; 65 66 66 purple_xfer_request_denied(px->xfer); 67 if (px->xfer) { 68 if (!purple_xfer_is_completed(px->xfer) && !purple_xfer_is_canceled(px->xfer)) { 69 purple_xfer_cancel_local(px->xfer); 70 } 71 px->xfer->ui_data = NULL; 72 purple_xfer_unref(px->xfer); 73 px->xfer = NULL; 74 } 75 } 76 77 static void prpl_xfer_free(struct file_transfer *ft) 78 { 79 struct prpl_xfer_data *px = ft->data; 80 struct purple_data *pd = px->ic->proto_data; 81 82 pd->filetransfers = g_slist_remove(pd->filetransfers, px); 83 84 if (px->xfer) { 85 px->xfer->ui_data = NULL; 86 purple_xfer_unref(px->xfer); 87 } 88 89 if (px->timeout) { 90 b_event_remove(px->timeout); 91 } 92 93 g_free(px->fn); 94 g_free(px->handle); 95 if (px->fd >= 0) { 96 close(px->fd); 97 } 98 g_free(px); 67 99 } 68 100 69 101 static void prplcb_xfer_new(PurpleXfer *xfer) 70 102 { 103 purple_xfer_ref(xfer); 104 71 105 if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) { 72 106 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 107 struct purple_data *pd; 73 108 74 109 xfer->ui_data = px; … … 77 112 px->fd = -1; 78 113 px->ic = purple_ic_by_pa(xfer->account); 114 115 pd = px->ic->proto_data; 116 pd->filetransfers = g_slist_prepend(pd->filetransfers, px); 79 117 80 118 purple_xfer_set_local_filename(xfer, px->fn); … … 112 150 px->ft->accept = prpl_xfer_accept; 113 151 px->ft->canceled = prpl_xfer_canceled; 152 px->ft->free = prpl_xfer_free; 114 153 px->ft->write_request = prpl_xfer_write_request; 115 154 … … 164 203 165 204 166 /* Generic (IM<>UI): */167 205 static void prplcb_xfer_destroy(PurpleXfer *xfer) 168 206 { 169 207 struct prpl_xfer_data *px = xfer->ui_data; 170 208 171 g_free(px->fn); 172 g_free(px->handle); 173 if (px->fd >= 0) { 174 close(px->fd); 175 } 176 g_free(px); 209 if (px) { 210 px->xfer = NULL; 211 } 177 212 } 178 213 … … 224 259 struct prpl_xfer_data *px = xfer->ui_data; 225 260 226 if (px ->ft) {261 if (px && px->ft) { 227 262 imcb_file_canceled(px->ic, px->ft, "Canceled by remote end"); 228 } else {263 } else if (px) { 229 264 /* px->ft == NULL for sends, because of the two stages. :-/ */ 230 265 imcb_error(px->ic, "File transfer cancelled by remote end"); … … 240 275 { 241 276 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 277 struct purple_data *pd; 242 278 char *dir, *basename; 243 279 244 280 ft->data = px; 245 281 px->ft = ft; 282 px->ft->free = prpl_xfer_free; 246 283 247 284 dir = g_strdup("/tmp/bitlbee-purple-ft.XXXXXX"); … … 272 309 px->handle = g_strdup(handle); 273 310 311 pd = px->ic->proto_data; 312 pd->filetransfers = g_slist_prepend(pd->filetransfers, px); 313 274 314 imcb_log(ic, 275 315 "Due to libpurple limitations, the file has to be cached locally before proceeding with the actual file transfer. Please wait..."); 276 316 277 b_timeout_add(0, purple_transfer_request_cb, ft);317 px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft); 278 318 } 279 319 … … 295 335 struct prpl_xfer_data *px = ft->data; 296 336 337 px->timeout = 0; 338 297 339 if (ft->write == NULL) { 298 340 ft->write = prpl_xfer_write; … … 322 364 px->ft = NULL; 323 365 } else { 324 b_timeout_add(0, purple_transfer_request_cb, ft);366 px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft); 325 367 } 326 368 327 369 return TRUE; 370 } 371 372 void purple_transfer_cancel_all(struct im_connection *ic) 373 { 374 struct purple_data *pd = ic->proto_data; 375 376 while (pd->filetransfers) { 377 struct prpl_xfer_data *px = pd->filetransfers->data; 378 379 if (px->ft) { 380 imcb_file_canceled(ic, px->ft, "Logging out"); 381 } 382 383 pd->filetransfers = g_slist_remove(pd->filetransfers, px); 384 } 328 385 } 329 386 -
protocols/purple/purple.c
rba52ac5 r537d9b9 43 43 const char *message, const char *who); 44 44 45 void purple_transfer_cancel_all(struct im_connection *ic); 46 45 47 /* purple_request_input specific stuff */ 46 48 typedef void (*ri_callback_t)(gpointer, const gchar *); … … 54 56 }; 55 57 58 struct purple_roomlist_data { 59 GSList *chats; 60 gint topic; 61 gboolean initialized; 62 }; 63 64 56 65 struct im_connection *purple_ic_by_pa(PurpleAccount *pa) 57 66 { … … 94 103 } 95 104 105 static char *purple_get_account_prpl_id(account_t *acc) 106 { 107 /* "oscar" is how non-purple bitlbee calls it, 108 * and it might be icq or aim, depending on the username */ 109 if (g_strcmp0(acc->prpl->name, "oscar") == 0) { 110 return (g_ascii_isdigit(acc->user[0])) ? "prpl-icq" : "prpl-aim"; 111 } 112 113 return acc->prpl->data; 114 } 115 96 116 static void purple_init(account_t *acc) 97 117 { 98 PurplePlugin *prpl = purple_plugins_find_with_id((char *) acc->prpl->data); 118 char *prpl_id = purple_get_account_prpl_id(acc); 119 PurplePlugin *prpl = purple_plugins_find_with_id(prpl_id); 99 120 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 100 121 PurpleAccount *pa; … … 262 283 /* Go through all away states to figure out if away/status messages 263 284 are possible. */ 264 pa = purple_account_new(acc->user, (char *) acc->prpl->data);285 pa = purple_account_new(acc->user, prpl_id); 265 286 for (st = purple_account_get_status_types(pa); st; st = st->next) { 266 287 PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data); … … 345 366 346 367 ic->proto_data = pd = g_new0(struct purple_data, 1); 347 pd->account = purple_account_new(acc->user, (char *) acc->prpl->data);368 pd->account = purple_account_new(acc->user, purple_get_account_prpl_id(acc)); 348 369 pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal, 349 370 NULL, g_free); … … 371 392 } 372 393 394 if (pd->filetransfers) { 395 purple_transfer_cancel_all(ic); 396 } 397 373 398 purple_account_set_enabled(pd->account, "BitlBee", FALSE); 374 399 purple_connections = g_slist_remove(purple_connections, ic); 375 400 purple_accounts_remove(pd->account); 401 imcb_chat_list_free(ic); 402 g_free(pd->chat_list_server); 376 403 g_hash_table_destroy(pd->input_requests); 377 404 g_free(pd); … … 673 700 } 674 701 702 void purple_chat_set_topic(struct groupchat *gc, char *topic) 703 { 704 PurpleConversation *pc = gc->data; 705 PurpleConvChat *pcc = PURPLE_CONV_CHAT(pc); 706 struct purple_data *pd = gc->ic->proto_data; 707 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 708 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 709 710 if (pi->set_chat_topic) { 711 pi->set_chat_topic(purple_account_get_connection(pd->account), 712 purple_conv_chat_get_id(pcc), 713 topic); 714 } 715 } 716 675 717 void purple_chat_kick(struct groupchat *gc, char *who, const char *message) 676 718 { … … 697 739 GHashTable *chat_hash; 698 740 PurpleConversation *conv; 741 struct groupchat *gc; 699 742 GList *info, *l; 700 743 … … 730 773 g_list_free(info); 731 774 775 /* do this before serv_join_chat to handle cases where prplcb_conv_new is called immediately (not async) */ 776 gc = imcb_chat_new(ic, room); 777 732 778 serv_join_chat(purple_account_get_connection(pd->account), chat_hash); 733 779 734 780 g_hash_table_destroy(chat_hash); 735 781 736 return imcb_chat_new(ic, room); 782 return gc; 783 } 784 785 void purple_chat_list(struct im_connection *ic, const char *server) 786 { 787 PurpleRoomlist *list; 788 struct purple_data *pd = ic->proto_data; 789 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 790 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 791 792 if (!pi || !pi->roomlist_get_list) { 793 imcb_log(ic, "Room listing unsupported by this purple plugin"); 794 return; 795 } 796 797 g_free(pd->chat_list_server); 798 pd->chat_list_server = (server && *server) ? g_strdup(server) : NULL; 799 800 list = purple_roomlist_get_list(pd->account->gc); 801 802 if (list) { 803 struct purple_roomlist_data *rld = list->ui_data; 804 rld->initialized = TRUE; 805 806 purple_roomlist_ref(list); 807 } 737 808 } 738 809 … … 970 1041 971 1042 /* Generic handler for IM or chat messages, covers write_chat, write_im and write_conv */ 972 static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message , guint32 bee_flags, time_t mtime)1043 static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message_, guint32 bee_flags, time_t mtime) 973 1044 { 974 1045 struct im_connection *ic = purple_ic_by_pa(conv->account); 975 1046 struct groupchat *gc = conv->ui_data; 1047 char *message = g_strdup(message_); 976 1048 PurpleBuddy *buddy; 977 1049 … … 982 1054 983 1055 if (conv->type == PURPLE_CONV_TYPE_IM) { 984 imcb_buddy_msg(ic, (char *) who, (char *)message, bee_flags, mtime);1056 imcb_buddy_msg(ic, who, message, bee_flags, mtime); 985 1057 } else if (gc) { 986 imcb_chat_msg(gc, who, (char *) message, bee_flags, mtime); 987 } 1058 imcb_chat_msg(gc, who, message, bee_flags, mtime); 1059 } 1060 1061 g_free(message); 988 1062 } 989 1063 … … 1171 1245 struct im_connection *ic = purple_ic_by_pa(account); 1172 1246 struct purple_data *pd = ic->proto_data; 1173 struct request_input_data *ri = g_new0(struct request_input_data, 1); 1174 guint id = pd->next_request_id++; 1247 struct request_input_data *ri; 1248 guint id; 1249 1250 /* hack so that jabber's chat list doesn't ask for conference server twice */ 1251 if (pd->chat_list_server && title && g_strcmp0(title, "Enter a Conference Server") == 0) { 1252 ((ri_callback_t) ok_cb)(user_data, pd->chat_list_server); 1253 g_free(pd->chat_list_server); 1254 pd->chat_list_server = NULL; 1255 return NULL; 1256 } 1257 1258 id = pd->next_request_id++; 1259 ri = g_new0(struct request_input_data, 1); 1175 1260 1176 1261 ri->id = id; … … 1182 1267 1183 1268 imcb_add_buddy(ic, ri->buddy, NULL); 1184 imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0); 1269 1270 if (title && *title) { 1271 imcb_buddy_msg(ic, ri->buddy, title, 0, 0); 1272 } 1273 1274 if (primary && *primary) { 1275 imcb_buddy_msg(ic, ri->buddy, primary, 0, 0); 1276 } 1277 1278 if (secondary && *secondary) { 1279 imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0); 1280 } 1185 1281 1186 1282 return ri; … … 1256 1352 prplcb_privacy_deny_added, /* deny_added */ 1257 1353 prplcb_privacy_deny_removed, /* deny_removed */ 1354 }; 1355 1356 static void prplcb_roomlist_create(PurpleRoomlist *list) 1357 { 1358 struct purple_roomlist_data *rld; 1359 1360 list->ui_data = rld = g_new0(struct purple_roomlist_data, 1); 1361 rld->topic = -1; 1362 } 1363 1364 static void prplcb_roomlist_set_fields(PurpleRoomlist *list, GList *fields) 1365 { 1366 gint topic = -1; 1367 GList *l; 1368 guint i; 1369 PurpleRoomlistField *field; 1370 struct purple_roomlist_data *rld = list->ui_data; 1371 1372 for (i = 0, l = fields; l; i++, l = l->next) { 1373 field = l->data; 1374 1375 /* Use the first visible string field as a fallback topic */ 1376 if (i != 0 && topic < 0 && !field->hidden && 1377 field->type == PURPLE_ROOMLIST_FIELD_STRING) { 1378 topic = i; 1379 } 1380 1381 if ((g_strcasecmp(field->name, "description") == 0) || 1382 (g_strcasecmp(field->name, "topic") == 0)) { 1383 if (field->type == PURPLE_ROOMLIST_FIELD_STRING) { 1384 rld->topic = i; 1385 } 1386 } 1387 } 1388 1389 if (rld->topic < 0) { 1390 rld->topic = topic; 1391 } 1392 } 1393 1394 static void prplcb_roomlist_add_room(PurpleRoomlist *list, PurpleRoomlistRoom *room) 1395 { 1396 bee_chat_info_t *ci; 1397 const char *title; 1398 const char *topic; 1399 GList *fields; 1400 struct purple_roomlist_data *rld = list->ui_data; 1401 1402 fields = purple_roomlist_room_get_fields(room); 1403 title = purple_roomlist_room_get_name(room); 1404 1405 if (rld->topic >= 0) { 1406 topic = g_list_nth_data(fields, rld->topic); 1407 } else { 1408 topic = NULL; 1409 } 1410 1411 ci = g_new(bee_chat_info_t, 1); 1412 ci->title = g_strdup(title); 1413 ci->topic = g_strdup(topic); 1414 rld->chats = g_slist_prepend(rld->chats, ci); 1415 } 1416 1417 static void prplcb_roomlist_in_progress(PurpleRoomlist *list, gboolean in_progress) 1418 { 1419 struct im_connection *ic; 1420 struct purple_data *pd; 1421 struct purple_roomlist_data *rld = list->ui_data; 1422 1423 if (in_progress || !rld) { 1424 return; 1425 } 1426 1427 ic = purple_ic_by_pa(list->account); 1428 imcb_chat_list_free(ic); 1429 1430 pd = ic->proto_data; 1431 g_free(pd->chat_list_server); 1432 pd->chat_list_server = NULL; 1433 1434 ic->chatlist = g_slist_reverse(rld->chats); 1435 rld->chats = NULL; 1436 1437 imcb_chat_list_finish(ic); 1438 1439 if (rld->initialized) { 1440 purple_roomlist_unref(list); 1441 } 1442 } 1443 1444 static void prplcb_roomlist_destroy(PurpleRoomlist *list) 1445 { 1446 g_free(list->ui_data); 1447 list->ui_data = NULL; 1448 } 1449 1450 static PurpleRoomlistUiOps bee_roomlist_uiops = 1451 { 1452 NULL, /* show_with_account */ 1453 prplcb_roomlist_create, /* create */ 1454 prplcb_roomlist_set_fields, /* set_fields */ 1455 prplcb_roomlist_add_room, /* add_room */ 1456 prplcb_roomlist_in_progress, /* in_progress */ 1457 prplcb_roomlist_destroy, /* destroy */ 1258 1458 }; 1259 1459 … … 1422 1622 purple_request_set_ui_ops(&bee_request_uiops); 1423 1623 purple_privacy_set_ui_ops(&bee_privacy_uiops); 1624 purple_roomlist_set_ui_ops(&bee_roomlist_uiops); 1424 1625 purple_notify_set_ui_ops(&bee_notify_uiops); 1425 1626 purple_accounts_set_ui_ops(&bee_account_uiops); … … 1438 1639 char *dir; 1439 1640 1641 if (purple_get_core() != NULL) { 1642 log_message(LOGLVL_ERROR, "libpurple already initialized. " 1643 "Please use inetd or ForkDaemon mode instead."); 1644 return; 1645 } 1646 1440 1647 g_assert((int) B_EV_IO_READ == (int) PURPLE_INPUT_READ); 1441 1648 g_assert((int) B_EV_IO_WRITE == (int) PURPLE_INPUT_WRITE); … … 1443 1650 dir = g_strdup_printf("%s/purple", global.conf->configdir); 1444 1651 purple_util_set_user_dir(dir); 1652 g_free(dir); 1653 1654 dir = g_strdup_printf("%s/purple", global.conf->plugindir); 1655 purple_plugins_add_search_path(dir); 1445 1656 g_free(dir); 1446 1657 … … 1506 1717 funcs.chat_with = purple_chat_with; 1507 1718 funcs.chat_invite = purple_chat_invite; 1719 funcs.chat_topic = purple_chat_set_topic; 1508 1720 funcs.chat_kick = purple_chat_kick; 1509 1721 funcs.chat_leave = purple_chat_leave; 1510 1722 funcs.chat_join = purple_chat_join; 1723 funcs.chat_list = purple_chat_list; 1511 1724 funcs.transfer_request = purple_transfer_request; 1512 1725 … … 1517 1730 for (prots = purple_plugins_get_protocols(); prots; prots = prots->next) { 1518 1731 PurplePlugin *prot = prots->data; 1732 PurplePluginProtocolInfo *pi = prot->info->extra_info; 1519 1733 struct prpl *ret; 1520 1734 … … 1530 1744 ret->name += 5; 1531 1745 } 1746 1747 if (pi->options & OPT_PROTO_NO_PASSWORD) { 1748 ret->options |= PRPL_OPT_NO_PASSWORD; 1749 } 1750 1751 if (pi->options & OPT_PROTO_PASSWORD_OPTIONAL) { 1752 ret->options |= PRPL_OPT_PASSWORD_OPTIONAL; 1753 } 1754 1532 1755 register_protocol(ret); 1533 1756 … … 1539 1762 ret = g_memdup(&funcs, sizeof(funcs)); 1540 1763 ret->name = "oscar"; 1541 ret->data = prot->info->id; 1764 /* purple_get_account_prpl_id() determines the actual protocol ID (icq/aim) */ 1765 ret->data = NULL; 1542 1766 register_protocol(ret); 1543 1767 } -
protocols/skype/skype.c
rba52ac5 r537d9b9 1763 1763 register_protocol(ret); 1764 1764 } 1765 1766 struct plugin_info *init_plugin_info(void) 1767 { 1768 static struct plugin_info info = { 1769 BITLBEE_ABI_VERSION_CODE, 1770 "skype", 1771 BITLBEE_VERSION, 1772 "Skype protocol plugin", 1773 NULL, 1774 NULL 1775 }; 1776 1777 return &info; 1778 } -
protocols/twitter/twitter.c
rba52ac5 r537d9b9 345 345 imcb_log(ic, "Getting contact list"); 346 346 twitter_get_friends_ids(ic, -1); 347 twitter_get_mutes_ids(ic, -1); 348 twitter_get_noretweets_ids(ic, -1); 347 349 } else { 348 350 twitter_main_loop_start(ic); … … 469 471 g_regex_match(regex, msg, 0, &match_info); 470 472 while (g_match_info_matches(match_info)) { 471 gchar * s, *url;473 gchar *url; 472 474 473 475 url = g_match_info_fetch(match_info, 2); 474 476 url_len_diff += target_len - g_utf8_strlen(url, -1); 475 477 476 /* Add another character for https://t.co/... URLs */477 if ((s = g_match_info_fetch(match_info, 3))) {478 url_len_diff += 1;479 g_free(s);480 }481 478 g_free(url); 482 479 g_match_info_next(match_info, NULL); … … 541 538 if (strcmp(acc->prpl->name, "twitter") == 0) { 542 539 def_url = TWITTER_API_URL; 543 def_tul = "2 2";540 def_tul = "23"; 544 541 def_mentions = "true"; 545 542 } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ … … 690 687 } 691 688 689 g_slist_foreach(td->mutes_ids, (GFunc) g_free, NULL); 690 g_slist_free(td->mutes_ids); 691 692 g_slist_foreach(td->noretweets_ids, (GFunc) g_free, NULL); 693 g_slist_free(td->noretweets_ids); 694 692 695 http_close(td->stream); 693 696 twitter_filter_remove_all(ic); … … 948 951 } else if ((g_strcasecmp(cmd[0], "favourite") == 0 || 949 952 g_strcasecmp(cmd[0], "favorite") == 0 || 950 g_strcasecmp(cmd[0], "fav") == 0) && cmd[1]) { 953 g_strcasecmp(cmd[0], "fav") == 0 || 954 g_strcasecmp(cmd[0], "like") == 0) && cmd[1]) { 951 955 if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) { 952 956 twitter_favourite_tweet(ic, id); … … 960 964 } else if (g_strcasecmp(cmd[0], "unfollow") == 0 && cmd[1]) { 961 965 twitter_remove_buddy(ic, cmd[1], NULL); 966 goto eof; 967 } else if (g_strcasecmp(cmd[0], "mute") == 0 && cmd[1]) { 968 twitter_mute_create_destroy(ic, cmd[1], 1); 969 goto eof; 970 } else if (g_strcasecmp(cmd[0], "unmute") == 0 && cmd[1]) { 971 twitter_mute_create_destroy(ic, cmd[1], 0); 962 972 goto eof; 963 973 } else if ((g_strcasecmp(cmd[0], "report") == 0 || … … 1082 1092 struct prpl *ret = g_new0(struct prpl, 1); 1083 1093 1084 ret->options = OPT_NOOTR;1094 ret->options = PRPL_OPT_NOOTR | PRPL_OPT_NO_PASSWORD; 1085 1095 ret->name = "twitter"; 1086 1096 ret->login = twitter_login; … … 1109 1119 ret = g_memdup(ret, sizeof(struct prpl)); 1110 1120 ret->name = "identica"; 1121 ret->options = PRPL_OPT_NOOTR; 1111 1122 register_protocol(ret); 1112 1123 } -
protocols/twitter/twitter.h
rba52ac5 r537d9b9 61 61 62 62 GSList *follow_ids; 63 GSList *mutes_ids; 64 GSList *noretweets_ids; 63 65 GSList *filters; 64 66 -
protocols/twitter/twitter_http.c
rba52ac5 r537d9b9 79 79 g_string_printf(request, "%s %s%s%s%s HTTP/1.1\r\n" 80 80 "Host: %s\r\n" 81 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",81 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n", 82 82 is_post ? "POST" : "GET", 83 83 base_url ? base_url->file : td->url_path, -
protocols/twitter/twitter_lib.c
rba52ac5 r537d9b9 245 245 246 246 static void twitter_http_get_friends_ids(struct http_request *req); 247 static void twitter_http_get_mutes_ids(struct http_request *req); 248 static void twitter_http_get_noretweets_ids(struct http_request *req); 247 249 248 250 /** … … 257 259 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 258 260 twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2); 261 262 g_free(args[1]); 263 } 264 265 /** 266 * Get the muted users ids. 267 */ 268 void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor) 269 { 270 char *args[2]; 271 272 args[0] = "cursor"; 273 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 274 twitter_http(ic, TWITTER_MUTES_IDS_URL, twitter_http_get_mutes_ids, ic, 0, args, 2); 275 276 g_free(args[1]); 277 } 278 279 /** 280 * Get the ids for users from whom we should ignore retweets. 281 */ 282 void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor) 283 { 284 char *args[2]; 285 286 args[0] = "cursor"; 287 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 288 twitter_http(ic, TWITTER_NORETWEETS_IDS_URL, twitter_http_get_noretweets_ids, ic, 0, args, 2); 259 289 260 290 g_free(args[1]); … … 334 364 twitter_get_users_lookup(ic); 335 365 } 366 367 txl->list = NULL; 368 txl_free(txl); 369 } 370 371 /** 372 * Callback for getting the mutes ids. 373 */ 374 static void twitter_http_get_mutes_ids(struct http_request *req) 375 { 376 struct im_connection *ic = req->data; 377 JSON_Value *parsed; 378 struct twitter_xml_list *txl; 379 struct twitter_data *td; 380 381 // Check if the connection is stil active 382 if (!g_slist_find(twitter_connections, ic)) { 383 return; 384 } 385 386 td = ic->proto_data; 387 388 if (req->status_code != 200) { 389 /* Fail silently */ 390 return; 391 } 392 393 // Parse the data. 394 if (!(parsed = twitter_parse_response(ic, req))) { 395 return; 396 } 397 398 txl = g_new0(struct twitter_xml_list, 1); 399 txl->list = td->mutes_ids; 400 401 /* mute ids API response is similar enough to friends response 402 to reuse this method */ 403 twitter_xt_get_friends_id_list(parsed, txl); 404 json_value_free(parsed); 405 406 td->mutes_ids = txl->list; 407 if (txl->next_cursor) { 408 /* Recurse while there are still more pages */ 409 twitter_get_mutes_ids(ic, txl->next_cursor); 410 } 411 412 txl->list = NULL; 413 txl_free(txl); 414 } 415 416 /** 417 * Callback for getting the no-retweets ids. 418 */ 419 static void twitter_http_get_noretweets_ids(struct http_request *req) 420 { 421 struct im_connection *ic = req->data; 422 JSON_Value *parsed; 423 struct twitter_xml_list *txl; 424 struct twitter_data *td; 425 426 // Check if the connection is stil active 427 if (!g_slist_find(twitter_connections, ic)) { 428 return; 429 } 430 431 if (req->status_code != 200) { 432 /* Fail silently */ 433 return; 434 } 435 436 td = ic->proto_data; 437 438 // Parse the data. 439 if (!(parsed = twitter_parse_response(ic, req))) { 440 return; 441 } 442 443 txl = g_new0(struct twitter_xml_list, 1); 444 txl->list = td->noretweets_ids; 445 446 // Process the retweet ids 447 txl->type = TXL_ID; 448 if (json_type(parsed) == JSONArray) { 449 JSON_Array *arr = json_array(parsed); 450 unsigned int i; 451 for (i = 0; i < json_array_get_count(arr); i++) { 452 jint id = json_array_get_integer(arr, i); 453 txl->list = g_slist_prepend(txl->list, 454 g_strdup_printf("%lld", id)); 455 } 456 } 457 458 json_value_free(parsed); 459 td->noretweets_ids = txl->list; 336 460 337 461 txl->list = NULL; … … 467 591 #endif 468 592 469 static void expand_entities(char **text, const JSON_Object *node );593 static void expand_entities(char **text, const JSON_Object *node, const JSON_Object *extended_node); 470 594 471 595 /** … … 479 603 static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node) 480 604 { 481 struct twitter_xml_status *txs ;605 struct twitter_xml_status *txs = {0}; 482 606 const JSON_Object *rt = NULL; 607 const JSON_Value *text_value = NULL; 608 const JSON_Object *extended_node = NULL; 483 609 484 610 if (!node) { … … 488 614 489 615 JSON_O_FOREACH(node, k, v) { 490 if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) { 491 // TODO: Huh strip html? In json? Not sure whether I have to.. 492 strip_html(txs->text); 616 if (strcmp("text", k) == 0 && json_type(v) == JSONString && text_value == NULL) { 617 text_value = v; 618 } else if (strcmp("full_text", k) == 0 && json_type(v) == JSONString) { 619 text_value = v; 620 } else if (strcmp("extended_tweet", k) == 0 && json_type(v) == JSONObject) { 621 text_value = json_object_get_value(json_object(v), "full_text"); 622 extended_node = json_object(v); 493 623 } else if (strcmp("retweeted_status", k) == 0 && (rt = json_object(v))) { 494 624 // Handling below. … … 516 646 struct twitter_xml_status *rtxs = twitter_xt_get_status(rt); 517 647 if (rtxs) { 518 g_free(txs->text);519 648 txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text); 520 649 txs->id = rtxs->id; 521 650 txs_free(rtxs); 522 651 } 523 } else { 524 expand_entities(&txs->text, node); 652 } else if (text_value && json_type(text_value) == JSONString) { 653 txs->text = g_strdup(json_string(text_value)); 654 strip_html(txs->text); 655 expand_entities(&txs->text, node, extended_node); 525 656 } 526 657 … … 564 695 } 565 696 566 expand_entities(&txs->text, node );697 expand_entities(&txs->text, node, NULL); 567 698 568 699 if (txs->text && txs->user && txs->id) { … … 574 705 } 575 706 576 static void expand_entities(char **text, const JSON_Object *node )577 { 578 JSON_Object *entities, * quoted;707 static void expand_entities(char **text, const JSON_Object *node, const JSON_Object *extended_node) 708 { 709 JSON_Object *entities, *extended_entities, *quoted; 579 710 char *quote_url = NULL, *quote_text = NULL; 580 711 … … 594 725 } 595 726 727 if (extended_node) { 728 extended_entities = json_object_get_object(extended_node, "entities"); 729 if (extended_entities) { 730 entities = extended_entities; 731 } 732 } 733 596 734 JSON_O_FOREACH(entities, k, v) { 597 735 int i; … … 837 975 struct twitter_data *td = ic->proto_data; 838 976 char *last_id_str; 977 char *uid_str; 839 978 840 979 if (status->user == NULL || status->text == NULL) { 980 return; 981 } 982 983 /* Check this is not a tweet that should be muted */ 984 uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, status->user->uid); 985 986 if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) { 987 g_free(uid_str); 988 return; 989 } 990 if (status->id != status->rt_id && g_slist_find_custom(td->noretweets_ids, uid_str, (GCompareFunc)strcmp)) { 991 g_free(uid_str); 841 992 return; 842 993 } … … 863 1014 set_setstr(&ic->acc->set, "_last_tweet", last_id_str); 864 1015 g_free(last_id_str); 1016 g_free(uid_str); 865 1017 } 866 1018 … … 880 1032 } 881 1033 882 ic->flags |= OPT_PONGED;883 1034 td = ic->proto_data; 884 1035 … … 896 1047 imc_logout(ic, TRUE); 897 1048 return; 1049 } 1050 1051 if (req == td->stream) { 1052 ic->flags |= OPT_PONGED; 898 1053 } 899 1054 … … 999 1154 JSON_Object *target = json_object_get_object(o, "target"); 1000 1155 const char *type = json_object_get_string(o, "event"); 1156 struct twitter_xml_user *us = NULL; 1157 struct twitter_xml_user *ut = NULL; 1001 1158 1002 1159 if (!type || !source || !target) { … … 1005 1162 1006 1163 if (strcmp(type, "follow") == 0) { 1007 struct twitter_xml_user *us = twitter_xt_get_user(source);1008 struct twitter_xml_user *ut = twitter_xt_get_user(target);1164 us = twitter_xt_get_user(source); 1165 ut = twitter_xt_get_user(target); 1009 1166 if (g_strcasecmp(us->screen_name, td->user) == 0) { 1010 1167 twitter_add_buddy(ic, ut->screen_name, ut->name); 1011 1168 } 1012 txu_free(us); 1013 txu_free(ut); 1014 } 1169 } else if (strcmp(type, "mute") == 0) { 1170 GSList *found; 1171 char *uid_str; 1172 ut = twitter_xt_get_user(target); 1173 uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid); 1174 if (!(found = g_slist_find_custom(td->mutes_ids, uid_str, 1175 (GCompareFunc)strcmp))) { 1176 td->mutes_ids = g_slist_prepend(td->mutes_ids, uid_str); 1177 } 1178 twitter_log(ic, "Muted user %s", ut->screen_name); 1179 if (getenv("BITLBEE_DEBUG")) { 1180 fprintf(stderr, "New mute: %s %"G_GUINT64_FORMAT"\n", 1181 ut->screen_name, ut->uid); 1182 } 1183 } else if (strcmp(type, "unmute") == 0) { 1184 GSList *found; 1185 char *uid_str; 1186 ut = twitter_xt_get_user(target); 1187 uid_str = g_strdup_printf("%" G_GUINT64_FORMAT, ut->uid); 1188 if ((found = g_slist_find_custom(td->mutes_ids, uid_str, 1189 (GCompareFunc)strcmp))) { 1190 char *found_str = found->data; 1191 td->mutes_ids = g_slist_delete_link(td->mutes_ids, found); 1192 g_free(found_str); 1193 } 1194 g_free(uid_str); 1195 twitter_log(ic, "Unmuted user %s", ut->screen_name); 1196 if (getenv("BITLBEE_DEBUG")) { 1197 fprintf(stderr, "New unmute: %s %"G_GUINT64_FORMAT"\n", 1198 ut->screen_name, ut->uid); 1199 } 1200 } 1201 1202 txu_free(us); 1203 txu_free(ut); 1015 1204 1016 1205 return TRUE; … … 1309 1498 td->flags &= ~TWITTER_GOT_TIMELINE; 1310 1499 1311 char *args[ 6];1500 char *args[8]; 1312 1501 args[0] = "cursor"; 1313 1502 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 1314 1503 args[2] = "include_entities"; 1315 1504 args[3] = "true"; 1505 args[4] = "tweet_mode"; 1506 args[5] = "extended"; 1316 1507 if (td->timeline_id) { 1317 args[ 4] = "since_id";1318 args[ 5] = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id);1508 args[6] = "since_id"; 1509 args[7] = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id); 1319 1510 } 1320 1511 1321 1512 if (twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, 1322 td->timeline_id ? 6 : 4) == NULL) {1513 td->timeline_id ? 8 : 6) == NULL) { 1323 1514 if (++td->http_fails >= 5) { 1324 1515 imcb_error(ic, "Could not retrieve %s: %s", … … 1331 1522 g_free(args[1]); 1332 1523 if (td->timeline_id) { 1333 g_free(args[ 5]);1524 g_free(args[7]); 1334 1525 } 1335 1526 } … … 1346 1537 td->flags &= ~TWITTER_GOT_MENTIONS; 1347 1538 1348 char *args[ 6];1539 char *args[8]; 1349 1540 args[0] = "cursor"; 1350 1541 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); … … 1358 1549 args[5] = g_strdup_printf("%d", set_getint(&ic->acc->set, "show_old_mentions")); 1359 1550 } 1551 args[6] = "tweet_mode"; 1552 args[7] = "extended"; 1360 1553 1361 1554 if (twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions, 1362 ic, 0, args, 6) == NULL) {1555 ic, 0, args, 8) == NULL) { 1363 1556 if (++td->http_fails >= 5) { 1364 1557 imcb_error(ic, "Could not retrieve %s: %s", … … 1529 1722 } 1530 1723 1724 /** 1725 * Mute or unmute a user 1726 */ 1727 void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create) 1728 { 1729 char *args[2]; 1730 1731 args[0] = "screen_name"; 1732 args[1] = who; 1733 twitter_http(ic, create ? TWITTER_MUTES_CREATE_URL : TWITTER_MUTES_DESTROY_URL, 1734 twitter_http_post, ic, 1, args, 2); 1735 } 1736 1531 1737 void twitter_status_destroy(struct im_connection *ic, guint64 id) 1532 1738 { -
protocols/twitter/twitter_lib.h
rba52ac5 r537d9b9 63 63 #define TWITTER_FRIENDS_IDS_URL "/friends/ids.json" 64 64 #define TWITTER_FOLLOWERS_IDS_URL "/followers/ids.json" 65 #define TWITTER_MUTES_IDS_URL "/mutes/users/ids.json" 66 #define TWITTER_NORETWEETS_IDS_URL "/friendships/no_retweets/ids.json" 65 67 66 68 /* Account URLs */ … … 76 78 #define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/" 77 79 80 /* Mute URLs */ 81 #define TWITTER_MUTES_CREATE_URL "/mutes/users/create.json" 82 #define TWITTER_MUTES_DESTROY_URL "/mutes/users/destroy.json" 83 78 84 /* Report spam */ 79 85 #define TWITTER_REPORT_SPAM_URL "/users/report_spam.json" … … 87 93 gboolean twitter_get_timeline(struct im_connection *ic, gint64 next_cursor); 88 94 void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor); 95 void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor); 96 void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor); 89 97 void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor); 90 98 … … 92 100 void twitter_direct_messages_new(struct im_connection *ic, char *who, char *message); 93 101 void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create); 102 void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create); 94 103 void twitter_status_destroy(struct im_connection *ic, guint64 id); 95 104 void twitter_status_retweet(struct im_connection *ic, guint64 id); -
root_commands.c
rba52ac5 r537d9b9 143 143 } 144 144 145 if (load) { 145 status = auth_check_pass(irc, irc->user->nick, password); 146 if (load && (status == STORAGE_OK)) { 146 147 status = storage_load(irc, password); 147 } else {148 status = storage_check_pass(irc->user->nick, password);149 148 } 150 149 … … 159 158 irc_rootmsg(irc, "Password accepted%s", 160 159 load ? ", settings and accounts loaded" : ""); 161 irc_setpass(irc, password);162 160 irc->status |= USTATUS_IDENTIFIED; 163 161 irc_umode_set(irc, "+R", 1); … … 268 266 storage_status_t status; 269 267 270 status = storage_remove(irc->user->nick, cmd[1]); 268 status = auth_check_pass(irc, irc->user->nick, cmd[1]); 269 if (status == STORAGE_OK) { 270 status = storage_remove(irc->user->nick); 271 } 272 271 273 switch (status) { 272 274 case STORAGE_NO_SUCH_USER: … … 340 342 int st; 341 343 344 if (s && s->flags & SET_LOCKED) { 345 irc_rootmsg(irc, "This setting can not be changed"); 346 return 0; 347 } 342 348 if (s && checkflags && checkflags(irc, s) == 0) { 343 349 return 0; … … 388 394 irc_rootmsg(irc, "This setting can only be changed when the account is %s-line", "on"); 389 395 return 0; 396 } else if (a->flags & ACC_FLAG_LOCKED && s && s->flags & ACC_SET_LOCKABLE) { 397 irc_rootmsg(irc, "This setting can not be changed for locked accounts"); 398 return 0; 390 399 } 391 400 … … 409 418 410 419 MIN_ARGS(3); 420 421 if (!global.conf->allow_account_add) { 422 irc_rootmsg(irc, "This server does not allow adding new accounts"); 423 return; 424 } 411 425 412 426 if (cmd[4] == NULL) { … … 456 470 irc_rootmsg(irc, "No need to enter a password for this " 457 471 "account since it's using OAuth"); 472 } else if (prpl->options & PRPL_OPT_NO_PASSWORD) { 473 *a->pass = '\0'; 474 } else if (prpl->options & PRPL_OPT_PASSWORD_OPTIONAL) { 475 *a->pass = '\0'; 476 irc_rootmsg(irc, "Passwords are optional for this account. " 477 "If you wish to enter the password with /OPER, do " 478 "account %s set -del password", a->tag); 458 479 } else { 459 480 irc_rootmsg(irc, "You can now use the /OPER command to " … … 465 486 } 466 487 } 488 } else if (prpl->options & PRPL_OPT_NO_PASSWORD) { 489 irc_rootmsg(irc, "Note: this account doesn't use password for login"); 467 490 } 468 491 … … 553 576 554 577 if (len >= 1 && g_strncasecmp(cmd[2], "del", len) == 0) { 555 if (a->ic) { 578 if (a->flags & ACC_FLAG_LOCKED) { 579 irc_rootmsg(irc, "Account is locked, can't delete"); 580 } 581 else if (a->ic) { 556 582 irc_rootmsg(irc, "Account is still logged in, can't delete"); 557 583 } else { … … 1108 1134 } 1109 1135 1136 static gint prplcmp(gconstpointer a, gconstpointer b) 1137 { 1138 const struct prpl *pa = a; 1139 const struct prpl *pb = b; 1140 1141 return g_strcasecmp(pa->name, pb->name); 1142 } 1143 1144 static void prplstr(GList *prpls, GString *gstr) 1145 { 1146 const char *last = NULL; 1147 GList *l; 1148 struct prpl *p; 1149 1150 prpls = g_list_copy(prpls); 1151 prpls = g_list_sort(prpls, prplcmp); 1152 1153 for (l = prpls; l; l = l->next) { 1154 p = l->data; 1155 1156 if (last && g_strcasecmp(p->name, last) == 0) { 1157 /* Ignore duplicates (mainly for libpurple) */ 1158 continue; 1159 } 1160 1161 if (gstr->len != 0) { 1162 g_string_append(gstr, ", "); 1163 } 1164 1165 g_string_append(gstr, p->name); 1166 last = p->name; 1167 } 1168 1169 g_list_free(prpls); 1170 } 1171 1172 static void cmd_plugins(irc_t *irc, char **cmd) 1173 { 1174 GList *prpls; 1175 GString *gstr; 1176 1177 #ifdef WITH_PLUGINS 1178 GList *l; 1179 struct plugin_info *info; 1180 1181 for (l = get_plugins(); l; l = l->next) { 1182 info = l->data; 1183 irc_rootmsg(irc, "%s:", info->name); 1184 irc_rootmsg(irc, " Version: %s", info->version); 1185 1186 if (info->description) { 1187 irc_rootmsg(irc, " Description: %s", info->description); 1188 } 1189 1190 if (info->author) { 1191 irc_rootmsg(irc, " Author: %s", info->author); 1192 } 1193 1194 if (info->url) { 1195 irc_rootmsg(irc, " URL: %s", info->url); 1196 } 1197 1198 irc_rootmsg(irc, ""); 1199 } 1200 #endif 1201 1202 gstr = g_string_new(NULL); 1203 prpls = get_protocols(); 1204 1205 if (prpls) { 1206 prplstr(prpls, gstr); 1207 irc_rootmsg(irc, "Enabled Protocols: %s", gstr->str); 1208 g_string_truncate(gstr, 0); 1209 } 1210 1211 prpls = get_protocols_disabled(); 1212 1213 if (prpls) { 1214 prplstr(prpls, gstr); 1215 irc_rootmsg(irc, "Disabled Protocols: %s", gstr->str); 1216 } 1217 1218 g_string_free(gstr, TRUE); 1219 } 1220 1110 1221 static void cmd_qlist(irc_t *irc, char **cmd) 1111 1222 { … … 1134 1245 1135 1246 if (g_strcasecmp(cmd[1], "add") == 0) { 1136 char *channel, *s; 1247 bee_chat_info_t *ci; 1248 char *channel, *room, *s; 1137 1249 struct irc_channel *ic; 1250 guint i; 1138 1251 1139 1252 MIN_ARGS(3); … … 1147 1260 } 1148 1261 1262 if (cmd[3][0] == '!') { 1263 if (!acc->ic || !(acc->ic->flags & OPT_LOGGED_IN)) { 1264 irc_rootmsg(irc, "Not logged in to account."); 1265 return; 1266 } else if (!acc->prpl->chat_list) { 1267 irc_rootmsg(irc, "Listing chatrooms not supported on that account."); 1268 return; 1269 } 1270 1271 i = g_ascii_strtoull(cmd[3] + 1, NULL, 10); 1272 ci = g_slist_nth_data(acc->ic->chatlist, i - 1); 1273 1274 if (ci == NULL) { 1275 irc_rootmsg(irc, "Invalid chatroom index"); 1276 return; 1277 } 1278 1279 room = ci->title; 1280 } else { 1281 room = cmd[3]; 1282 } 1283 1149 1284 if (cmd[4] == NULL) { 1150 channel = g_strdup( cmd[3]);1285 channel = g_strdup(room); 1151 1286 if ((s = strchr(channel, '@'))) { 1152 1287 *s = 0; … … 1168 1303 set_setstr(&ic->set, "chat_type", "room") && 1169 1304 set_setstr(&ic->set, "account", cmd[2]) && 1170 set_setstr(&ic->set, "room", cmd[3])) {1305 set_setstr(&ic->set, "room", room)) { 1171 1306 irc_rootmsg(irc, "Chatroom successfully added."); 1172 1307 } else { … … 1178 1313 } 1179 1314 g_free(channel); 1315 } else if (g_strcasecmp(cmd[1], "list") == 0) { 1316 MIN_ARGS(2); 1317 1318 if (!(acc = account_get(irc->b, cmd[2]))) { 1319 irc_rootmsg(irc, "Invalid account"); 1320 return; 1321 } else if (!acc->ic || !(acc->ic->flags & OPT_LOGGED_IN)) { 1322 irc_rootmsg(irc, "Not logged in to account."); 1323 return; 1324 } else if (!acc->prpl->chat_list) { 1325 irc_rootmsg(irc, "Listing chatrooms not supported on that account."); 1326 return; 1327 } 1328 1329 acc->prpl->chat_list(acc->ic, cmd[3]); 1180 1330 } else if (g_strcasecmp(cmd[1], "with") == 0) { 1181 1331 irc_user_t *iu; … … 1192 1342 irc_rootmsg(irc, "Can't open a groupchat with %s.", cmd[2]); 1193 1343 } 1194 } else if (g_strcasecmp(cmd[1], "list") == 0 || 1195 g_strcasecmp(cmd[1], "set") == 0 || 1344 } else if (g_strcasecmp(cmd[1], "set") == 0 || 1196 1345 g_strcasecmp(cmd[1], "del") == 0) { 1197 1346 irc_rootmsg(irc, … … 1203 1352 cmd[1]); 1204 1353 } 1354 } 1355 1356 /* some arbitrary numbers */ 1357 #define CHAT_TITLE_LEN_MIN 20 1358 #define CHAT_TITLE_LEN_MAX 100 1359 1360 void cmd_chat_list_finish(struct im_connection *ic) 1361 { 1362 account_t *acc = ic->acc; 1363 bee_chat_info_t *ci; 1364 char *hformat, *iformat, *topic, *padded; 1365 GSList *l; 1366 guint i = 0; 1367 long title_len, new_len; 1368 irc_t *irc = ic->bee->ui_data; 1369 1370 if (ic->chatlist == NULL) { 1371 irc_rootmsg(irc, "No existing chatrooms"); 1372 return; 1373 } 1374 1375 /* find a reasonable width for the table */ 1376 title_len = CHAT_TITLE_LEN_MIN; 1377 1378 for (l = ic->chatlist; l; l = l->next) { 1379 ci = l->data; 1380 new_len = g_utf8_strlen(ci->title, -1); 1381 1382 if (new_len >= CHAT_TITLE_LEN_MAX) { 1383 title_len = CHAT_TITLE_LEN_MAX; 1384 break; 1385 } else if (title_len < new_len) { 1386 title_len = new_len; 1387 } 1388 } 1389 1390 if (strchr(irc->umode, 'b') != NULL) { 1391 hformat = "%s\t%s\t%s"; 1392 iformat = "%u\t%s\t%s"; 1393 } else { 1394 hformat = "%s %s %s"; 1395 iformat = "%5u %s %s"; 1396 } 1397 1398 padded = str_pad_and_truncate("Title", title_len, NULL); 1399 irc_rootmsg(irc, hformat, "Index", padded, "Topic"); 1400 g_free(padded); 1401 1402 for (l = ic->chatlist; l; l = l->next) { 1403 ci = l->data; 1404 topic = ci->topic ? ci->topic : ""; 1405 1406 padded = str_pad_and_truncate(ci->title, title_len, "[...]"); 1407 irc_rootmsg(irc, iformat, ++i, padded, topic); 1408 g_free(padded); 1409 } 1410 1411 irc_rootmsg(irc, "%u %s chatrooms", i, acc->tag); 1205 1412 } 1206 1413 … … 1256 1463 { 1257 1464 GSList *files = irc->file_transfers; 1465 GSList *next; 1258 1466 1259 1467 enum { LIST, REJECT, CANCEL }; … … 1273 1481 } 1274 1482 1275 for (; files; files = g_slist_next(files)) { 1483 for (; files; files = next) { 1484 next = files->next; 1276 1485 file_transfer_t *file = files->data; 1277 1486 … … 1357 1566 { "nick", 1, cmd_nick, 0 }, 1358 1567 { "no", 0, cmd_yesno, 0 }, 1568 { "plugins", 0, cmd_plugins, 0 }, 1359 1569 { "qlist", 0, cmd_qlist, 0 }, 1360 1570 { "register", 0, cmd_register, 0 }, -
set.h
rba52ac5 r537d9b9 49 49 SET_PASSWORD = 0x0400, /* Value shows up in settings list as "********". */ 50 50 SET_HIDDEN_DEFAULT = 0x0800, /* Hide unless changed from default. */ 51 SET_LOCKED = 0x1000 /* Setting is locked, don't allow changing it */ 51 52 } set_flags_t; 52 53 -
storage.c
rba52ac5 r537d9b9 29 29 #include "bitlbee.h" 30 30 31 extern storage_t storage_text;32 31 extern storage_t storage_xml; 33 32 … … 92 91 } 93 92 94 storage_status_t storage_check_pass( const char *nick, const char *password)93 storage_status_t storage_check_pass(irc_t *irc, const char *nick, const char *password) 95 94 { 96 95 GList *gl; … … 102 101 storage_status_t status; 103 102 104 status = st->check_pass( nick, password);103 status = st->check_pass(irc, nick, password); 105 104 if (status != STORAGE_NO_SUCH_USER) { 106 105 return status; … … 176 175 } 177 176 178 storage_status_t storage_remove(const char *nick , const char *password)177 storage_status_t storage_remove(const char *nick) 179 178 { 180 179 GList *gl; … … 190 189 storage_status_t status; 191 190 192 status = st->remove(nick , password);191 status = st->remove(nick); 193 192 ok |= status == STORAGE_OK; 194 193 if (status != STORAGE_NO_SUCH_USER && status != STORAGE_OK) { -
storage.h
rba52ac5 r537d9b9 31 31 STORAGE_NO_SUCH_USER, 32 32 STORAGE_INVALID_PASSWORD, 33 STORAGE_CHECK_BACKEND, 33 34 STORAGE_ALREADY_EXISTS, 34 35 STORAGE_OTHER_ERROR /* Error that isn't caused by user input, such as … … 43 44 void (*init)(void); 44 45 45 storage_status_t (*check_pass)( const char *nick, const char *password);46 storage_status_t (*check_pass)(irc_t *irc, const char *nick, const char *password); 46 47 47 48 storage_status_t (*load)(irc_t *irc, const char *password); 48 49 storage_status_t (*save)(irc_t *irc, int overwrite); 49 storage_status_t (*remove)(const char *nick , const char *password);50 storage_status_t (*remove)(const char *nick); 50 51 51 52 /* May be NULL if not supported by backend */ … … 53 54 } storage_t; 54 55 55 storage_status_t storage_check_pass( const char *nick, const char *password);56 storage_status_t storage_check_pass(irc_t *irc, const char *nick, const char *password); 56 57 57 58 storage_status_t storage_load(irc_t * irc, const char *password); 58 59 storage_status_t storage_save(irc_t *irc, char *password, int overwrite); 59 storage_status_t storage_remove(const char *nick , const char *password);60 storage_status_t storage_remove(const char *nick); 60 61 61 62 void register_storage_backend(storage_t *); -
storage_xml.c
rba52ac5 r537d9b9 34 34 35 35 typedef enum { 36 XML_PASS_CHECK_ONLY = -1, 37 XML_PASS_UNKNOWN = 0, 38 XML_PASS_WRONG, 39 XML_PASS_OK 40 } xml_pass_st; 36 XML_PASS_CHECK = 0, 37 XML_LOAD 38 } xml_action; 41 39 42 40 /* To make it easier later when extending the format: */ … … 65 63 { 66 64 struct xt_node *c; 65 struct set *s; 67 66 68 67 for (c = node->children; (c = xt_find_node(c, "setting")); c = c->next) { 69 68 char *name = xt_find_attr(c, "name"); 69 char *locked = xt_find_attr(c, "locked"); 70 70 71 71 if (!name) { … … 80 80 } 81 81 set_setstr(head, name, c->text); 82 if (locked && !g_strcasecmp(locked, "true")) { 83 s = set_find(head, name); 84 if (s) { 85 s->flags |= SET_LOCKED; 86 } 87 } 82 88 } 83 89 } … … 105 111 { 106 112 struct xml_parsedata *xd = data; 107 char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag ;113 char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag, *locked; 108 114 char *pass_b64 = NULL; 109 115 unsigned char *pass_cr = NULL; … … 118 124 autoconnect = xt_find_attr(node, "autoconnect"); 119 125 tag = xt_find_attr(node, "tag"); 126 locked = xt_find_attr(node, "locked"); 120 127 121 128 protocol = xt_find_attr(node, "protocol"); … … 130 137 if (!handle || !pass_b64 || !protocol || !prpl) { 131 138 return XT_ABORT; 132 } else if ((pass_len = base64_decode(pass_b64, (unsigned char **) &pass_cr)) && 133 arc_decode(pass_cr, pass_len, &password, xd->given_pass) >= 0) { 134 acc = account_add(xd->irc->b, prpl, handle, password); 135 if (server) { 136 set_setstr(&acc->set, "server", server); 137 } 138 if (autoconnect) { 139 set_setstr(&acc->set, "auto_connect", autoconnect); 140 } 141 if (tag) { 142 set_setstr(&acc->set, "tag", tag); 143 } 144 if (prpl == &protocol_missing) { 145 set_t *s = set_add(&acc->set, "_protocol_name", protocol, NULL, NULL); 146 s->flags |= SET_HIDDEN | SET_NOSAVE | 147 ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY; 148 } 139 } 140 141 pass_len = base64_decode(pass_b64, (unsigned char **) &pass_cr); 142 if (xd->irc->auth_backend) { 143 password = g_strdup((char *)pass_cr); 149 144 } else { 150 g_free(pass_cr); 151 g_free(password); 152 return XT_ABORT; 145 pass_len = arc_decode(pass_cr, pass_len, &password, xd->given_pass); 146 if (pass_len < 0) { 147 g_free(pass_cr); 148 g_free(password); 149 return XT_ABORT; 150 } 151 } 152 153 acc = account_add(xd->irc->b, prpl, handle, password); 154 if (server) { 155 set_setstr(&acc->set, "server", server); 156 } 157 if (autoconnect) { 158 set_setstr(&acc->set, "auto_connect", autoconnect); 159 } 160 if (tag) { 161 set_setstr(&acc->set, "tag", tag); 162 } 163 if (locked && !g_strcasecmp(locked, "true")) { 164 acc->flags |= ACC_FLAG_LOCKED; 165 } 166 if (prpl == &protocol_missing) { 167 set_t *s = set_add(&acc->set, "_protocol_name", protocol, NULL, NULL); 168 s->flags |= SET_HIDDEN | SET_NOSAVE | 169 ACC_SET_OFFLINE_ONLY | ACC_SET_ONLINE_ONLY; 153 170 } 154 171 … … 210 227 }; 211 228 212 static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_ pass_staction)229 static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_action action) 213 230 { 214 231 struct xml_parsedata xd[1]; … … 252 269 } 253 270 254 {271 if (action == XML_PASS_CHECK) { 255 272 char *nick = xt_find_attr(node, "nick"); 256 273 char *pass = xt_find_attr(node, "password"); 257 258 if (!nick || !pass) { 274 char *backend = xt_find_attr(node, "auth_backend"); 275 276 if (!nick || !(pass || backend)) { 259 277 goto error; 278 } 279 280 if (backend) { 281 g_free(xd->irc->auth_backend); 282 xd->irc->auth_backend = g_strdup(backend); 283 ret = STORAGE_CHECK_BACKEND; 260 284 } else if ((st = md5_verify_password(xd->given_pass, pass)) != 0) { 261 285 ret = STORAGE_INVALID_PASSWORD; 262 goto error; 263 } 264 } 265 266 if (action == XML_PASS_CHECK_ONLY) { 267 ret = STORAGE_OK; 268 goto error; 269 } 270 271 /* DO NOT call xt_handle() before verifying the password! */ 286 } else { 287 ret = STORAGE_OK; 288 } 289 goto error; 290 } 291 272 292 if (xt_handle(xp, NULL, 1) == XT_HANDLED) { 273 293 ret = STORAGE_OK; … … 284 304 static storage_status_t xml_load(irc_t *irc, const char *password) 285 305 { 286 return xml_load_real(irc, irc->user->nick, password, XML_ PASS_UNKNOWN);287 } 288 289 static storage_status_t xml_check_pass( const char *my_nick, const char *password)290 { 291 return xml_load_real( NULL, my_nick, password, XML_PASS_CHECK_ONLY);306 return xml_load_real(irc, irc->user->nick, password, XML_LOAD); 307 } 308 309 static storage_status_t xml_check_pass(irc_t *irc, const char *my_nick, const char *password) 310 { 311 return xml_load_real(irc, my_nick, password, XML_PASS_CHECK); 292 312 } 293 313 … … 304 324 struct xt_node *root, *cur; 305 325 306 /* Generate a salted md5sum of the password. Use 5 bytes for the salt307 (to prevent dictionary lookups of passwords) to end up with a 21-308 byte password hash, more convenient for base64 encoding. */309 random_bytes(pass_md5 + 16, 5);310 md5_init(&md5_state);311 md5_append(&md5_state, (md5_byte_t *) irc->password, strlen(irc->password));312 md5_append(&md5_state, pass_md5 + 16, 5); /* Add the salt. */313 md5_finish(&md5_state, pass_md5);314 /* Save the hash in base64-encoded form. */315 pass_buf = base64_encode(pass_md5, 21);316 317 326 root = cur = xt_new_node("user", NULL, NULL); 327 if (irc->auth_backend) { 328 xt_add_attr(cur, "auth_backend", irc->auth_backend); 329 } else { 330 /* Generate a salted md5sum of the password. Use 5 bytes for the salt 331 (to prevent dictionary lookups of passwords) to end up with a 21- 332 byte password hash, more convenient for base64 encoding. */ 333 random_bytes(pass_md5 + 16, 5); 334 md5_init(&md5_state); 335 md5_append(&md5_state, (md5_byte_t *) irc->password, strlen(irc->password)); 336 md5_append(&md5_state, pass_md5 + 16, 5); /* Add the salt. */ 337 md5_finish(&md5_state, pass_md5); 338 /* Save the hash in base64-encoded form. */ 339 pass_buf = base64_encode(pass_md5, 21); 340 xt_add_attr(cur, "password", pass_buf); 341 g_free(pass_buf); 342 } 343 318 344 xt_add_attr(cur, "nick", irc->user->nick); 319 xt_add_attr(cur, "password", pass_buf);320 345 xt_add_attr(cur, "version", XML_FORMAT_VERSION); 321 322 g_free(pass_buf);323 346 324 347 xml_generate_settings(cur, &irc->b->set); … … 331 354 int pass_len; 332 355 333 pass_len = arc_encode(acc->pass, strlen(acc->pass), (unsigned char **) &pass_cr, irc->password, 12); 334 pass_b64 = base64_encode(pass_cr, pass_len); 335 g_free(pass_cr); 356 if(irc->auth_backend) { 357 /* If we don't "own" the password, it may change without us 358 * knowing, so we cannot encrypt the data, as we then may not be 359 * able to decrypt it */ 360 pass_b64 = base64_encode((unsigned char *)acc->pass, strlen(acc->pass)); 361 } else { 362 pass_len = arc_encode(acc->pass, strlen(acc->pass), (unsigned char **) &pass_cr, irc->password, 12); 363 pass_b64 = base64_encode(pass_cr, pass_len); 364 g_free(pass_cr); 365 } 336 366 337 367 cur = xt_new_node("account", NULL, NULL); … … 348 378 xt_add_attr(cur, "server", acc->server); 349 379 } 380 if (acc->flags & ACC_FLAG_LOCKED) { 381 xt_add_attr(cur, "locked", "true"); 382 } 350 383 351 384 g_free(pass_b64); … … 392 425 xt_add_child(cur, xset = xt_new_node("setting", set->value, NULL)); 393 426 xt_add_attr(xset, "name", set->key); 427 if (set->flags & SET_LOCKED) { 428 xt_add_attr(xset, "locked", "true"); 429 } 394 430 } 395 431 } … … 450 486 451 487 452 static storage_status_t xml_remove(const char *nick , const char *password)488 static storage_status_t xml_remove(const char *nick) 453 489 { 454 490 char s[512], *lc; 455 storage_status_t status;456 457 status = xml_check_pass(nick, password);458 if (status != STORAGE_OK) {459 return status;460 }461 491 462 492 lc = g_strdup(nick); -
tests/Makefile
rba52ac5 r537d9b9 15 15 distclean: clean 16 16 17 main_objs = bitlbee.o conf.o dcc.o help.o ipc.o irc.o irc_cap.o irc_channel.o irc_commands.o irc_im.o irc_send.o irc_user.o irc_util.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o17 main_objs = bitlbee.o conf.o dcc.o help.o ipc.o irc.o irc_cap.o irc_channel.o irc_commands.o irc_im.o irc_send.o irc_user.o irc_util.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) auth.o $(AUTH_OBJS) 18 18 19 19 test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_set.o check_jabber_sasl.o check_jabber_util.o -
tests/check_jabber_util.c
rba52ac5 r537d9b9 103 103 fail_unless(jabber_compare_jid("bugtest@google.com/A", "bugtest@google.com/A")); 104 104 fail_if(jabber_compare_jid("", "bugtest@google.com/A")); 105 fail_if(jabber_compare_jid(NULL, "")); 106 fail_if(jabber_compare_jid("", NULL)); 105 107 } 106 108 -
tests/check_util.c
rba52ac5 r537d9b9 137 137 5, 138 138 "aaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\na", 139 }, 140 { 141 "áááááááááá", 142 11, 143 "ááááá\nááááá", 139 144 }, 140 145 { -
unix.c
rba52ac5 r537d9b9 80 80 } 81 81 82 if (global.conf->runmode == RUNMODE_INETD) { 83 log_link(LOGLVL_ERROR, LOGOUTPUT_IRC); 84 log_link(LOGLVL_WARNING, LOGOUTPUT_IRC); 85 } else { 86 log_link(LOGLVL_ERROR, LOGOUTPUT_CONSOLE); 87 log_link(LOGLVL_WARNING, LOGOUTPUT_CONSOLE); 88 } 89 82 90 b_main_init(); 83 91 … … 104 112 } 105 113 114 global.auth = auth_init(global.conf->auth_backend); 115 if (global.conf->auth_backend && global.auth == NULL) { 116 log_message(LOGLVL_ERROR, "Unable to load authentication backend '%s'", global.conf->auth_backend); 117 return(1); 118 } 119 106 120 if (global.conf->runmode == RUNMODE_INETD) { 107 log_link(LOGLVL_ERROR, LOGOUTPUT_IRC);108 log_link(LOGLVL_WARNING, LOGOUTPUT_IRC);109 110 121 i = bitlbee_inetd_init(); 111 122 log_message(LOGLVL_INFO, "%s %s starting in inetd mode.", PACKAGE, BITLBEE_VERSION); 112 123 113 124 } else if (global.conf->runmode == RUNMODE_DAEMON) { 114 log_link(LOGLVL_ERROR, LOGOUTPUT_CONSOLE);115 log_link(LOGLVL_WARNING, LOGOUTPUT_CONSOLE);116 117 125 i = bitlbee_daemon_init(); 118 126 log_message(LOGLVL_INFO, "%s %s starting in daemon mode.", PACKAGE, BITLBEE_VERSION); 119 127 } else if (global.conf->runmode == RUNMODE_FORKDAEMON) { 120 log_link(LOGLVL_ERROR, LOGOUTPUT_CONSOLE);121 log_link(LOGLVL_WARNING, LOGOUTPUT_CONSOLE);122 123 128 /* In case the operator requests a restart, we need this. */ 124 129 old_cwd = g_malloc(256);
Note: See TracChangeset
for help on using the changeset viewer.