Changes in / [537d9b9:ba52ac5]
- Files:
-
- 4 deleted
- 70 edited
Legend:
- Unmodified
- Added
- Removed
-
.travis.yml
r537d9b9 rba52ac5 3 3 4 4 script: 5 - ./configure --pam=1 --ldap=15 - ./configure 6 6 - make check 7 7 - BITLBEE_SKYPE=plugin dpkg-buildpackage -uc -us -d … … 29 29 - libpurple-dev 30 30 - check 31 - libpam0g-dev32 - libldap2-dev33 31 coverity_scan: 34 32 project: … … 36 34 description: "An IRC to other chat networks gateway" 37 35 notification_email: dx@dxzone.com.ar 38 build_command_prepend: ./configure --otr=1 --debug=1 --pam=1 --ldap=136 build_command_prepend: ./configure --otr=1 --debug=1 39 37 build_command: make 40 38 branch_pattern: coverity_scan -
Makefile
r537d9b9 rba52ac5 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) auth.o $(AUTH_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) 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
r537d9b9 rba52ac5 52 52 # AuthMode = Open 53 53 54 ## AuthBackend55 ##56 ## By default, the authentication data for a user is stored in the storage57 ## backend. If you want to authenticate against another authentication system58 ## (e.g. ldap), you can specify that here.59 ##60 ## Beware that this disables password changes and causes passwords for the61 ## accounts people create to be stored in plain text instead of encrypted with62 ## 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 = storage71 #72 73 54 ## AuthPassword 74 55 ## … … 88 69 ## or 89 70 # OperPassword = md5:I0mnZbn1t4R731zzRdDN2/pK7lRX 90 91 ## AllowAccountAdd92 ##93 ## Whether to allow registered and identified users to add new accounts using94 ## 'account add'95 ##96 # AllowAccountAdd 197 71 98 72 ## HostName -
bitlbee.h
r537d9b9 rba52ac5 36 36 37 37 #define PACKAGE "BitlBee" 38 #define BITLBEE_VERSION "3.4. 2"38 #define BITLBEE_VERSION "3.4.1" 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, 2) 42 #define BITLBEE_ABI_VERSION_CODE 1 41 #define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 1) 43 42 44 43 #define MAX_STRING 511 … … 134 133 #include "irc.h" 135 134 #include "storage.h" 136 #include "auth.h"137 135 #include "set.h" 138 136 #include "nogaim.h" … … 156 154 conf_t *conf; 157 155 GList *storage; /* The first backend in the list will be used for saving */ 158 GList *auth; /* Authentication backends */159 156 char *helpfile; 160 157 int restart; … … 173 170 gboolean root_command_add(const char *command, int params, void (*func)(irc_t *, char **args), int flags); 174 171 gboolean cmd_identify_finish(gpointer data, gint fd, b_input_condition cond); 175 void cmd_chat_list_finish(struct im_connection *ic);176 172 gboolean bitlbee_shutdown(gpointer data, gint fd, b_input_condition cond); 177 173 -
conf.c
r537d9b9 rba52ac5 55 55 conf->runmode = RUNMODE_INETD; 56 56 conf->authmode = AUTHMODE_OPEN; 57 conf->auth_backend = NULL;58 57 conf->auth_pass = NULL; 59 58 conf->oper_pass = NULL; 60 conf->allow_account_add = 1;61 59 conf->configdir = g_strdup(CONFIG); 62 60 conf->plugindir = g_strdup(PLUGINDIR); … … 242 240 conf->authmode = AUTHMODE_OPEN; 243 241 } 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 }255 242 } else if (g_strcasecmp(ini->key, "authpassword") == 0) { 256 243 g_free(conf->auth_pass); … … 259 246 g_free(conf->oper_pass); 260 247 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);267 248 } else if (g_strcasecmp(ini->key, "hostname") == 0) { 268 249 g_free(conf->hostname); -
conf.h
r537d9b9 rba52ac5 37 37 runmode_t runmode; 38 38 authmode_t authmode; 39 char *auth_backend;40 39 char *auth_pass; 41 40 char *oper_pass; 42 int allow_account_add;43 41 char *hostname; 44 42 char *configdir; -
configure
r537d9b9 rba52ac5 54 54 ssl=auto 55 55 56 pam=057 ldap=058 59 56 pie=1 60 57 61 58 arch=$(uname -s) 59 cpu=$(uname -m) 62 60 63 61 GLIB_MIN_VERSION=2.16 … … 140 138 --rpc=0/1 Disable/enable RPC plugin interface $rpc 141 139 142 --pam=0/1 Disable/enable PAM authentication $pam143 --ldap=0/1 Disable/enable LDAP authentication $ldap144 145 140 --doc=0/1 Disable/enable help.txt generation $doc 146 141 --debug=0/1 Disable/enable debugging $debug … … 205 200 206 201 TARGET=$target 202 ARCH=$arch 203 CPU=$cpu 207 204 208 205 INSTALL=install -p … … 252 249 #define PIDFILE "$pidfile" 253 250 #define IPCSOCKET "$ipcsocket" 251 #define ARCH "$arch" 252 #define CPU "$cpu" 254 253 EOF 255 254 … … 349 348 fi 350 349 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 350 if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG glib-2.0; then 358 351 if $PKG_CONFIG glib-2.0 --atleast-version=$GLIB_MIN_VERSION; then 359 352 cat<<EOF >>Makefile.settings … … 648 641 done 649 642 echo "STORAGE_OBJS="$STORAGE_OBJS >> Makefile.settings 650 651 authobjs=652 authlibs=653 if [ "$pam" = 0 ]; then654 echo '#undef WITH_PAM' >> config.h655 else656 if ! echo '#include <security/pam_appl.h>' | $CC -E - >/dev/null 2>/dev/null; then657 echo 'Cannot find libpam development libraries, aborting. (Install libpam0g-dev?)'658 exit 1659 fi660 echo '#define WITH_PAM' >> config.h661 authobjs=$authobjs'auth_pam.o '662 authlibs=$authlibs'-lpam '663 fi664 if [ "$ldap" = 0 ]; then665 echo '#undef WITH_LDAP' >> config.h666 else667 if ! echo '#include <ldap.h>' | $CC -E - >/dev/null 2>/dev/null; then668 echo 'Cannot find libldap development libraries, aborting. (Install libldap2-dev?)'669 exit 1670 fi671 echo '#define WITH_LDAP' >> config.h672 authobjs=$authobjs'auth_ldap.o '673 authlibs=$authlibs'-lldap '674 fi675 echo AUTH_OBJS=$authobjs >> Makefile.settings676 echo EFLAGS+=$authlibs >> Makefile.settings677 643 678 644 if [ "$strip" = 0 ]; then -
debian/bitlbee-common.postinst
r537d9b9 rba52ac5 9 9 10 10 CONFDIR=/var/lib/bitlbee/ 11 12 update-rc.d bitlbee defaults > /dev/null 2>&1 11 13 12 14 ## Load default option. Don't want to put this in debconf (yet?) … … 64 66 fi 65 67 66 if [ "$BITLBEE_UPGRADE_DONT_RESTART" != "1" -a -n "$2" -a -x "/etc/init.d/bitlbee"]; then68 if [ "$BITLBEE_UPGRADE_DONT_RESTART" != "1" -a -n "$2" ]; then 67 69 invoke-rc.d bitlbee restart 68 70 fi … … 90 92 fi 91 93 92 #DEBHELPER# 94 if [ -z "$2" ]; then 95 invoke-rc.d bitlbee start 96 fi -
debian/bitlbee-common.postrm
r537d9b9 rba52ac5 3 3 set -e 4 4 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 5 [ "$1" = "purge" ] || exit 0 6 7 if [ -e /usr/share/debconf/confmodule ]; then 8 . /usr/share/debconf/confmodule; 9 db_purge; 9 10 fi 10 11 11 #DEBHELPER# 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 -
debian/bitlbee-common.prerm
r537d9b9 rba52ac5 11 11 mv /usr/share/bitlbee/help.txt /usr/share/bitlbee/help.upgrading 12 12 fi 13 else 14 invoke-rc.d bitlbee stop 13 15 fi 14 15 #DEBHELPER# -
debian/bitlbee.prerm
r537d9b9 rba52ac5 6 6 invoke-rc.d bitlbee stop 7 7 fi 8 9 #DEBHELPER# -
debian/changelog
r537d9b9 rba52ac5 1 bitlbee (3.4.2-1) unstable; urgency=medium2 3 [ Jelmer Vernooij ]4 * Make the build reproducible by not encoding ARCH / CPU defines in5 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 +010015 16 1 bitlbee (3.4.1-1) unstable; urgency=medium 17 2 -
debian/control
r537d9b9 rba52ac5 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. 87 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)5 Uploaders: Jelmer Vernooij <jelmer@debian.org> 6 Standards-Version: 3.9.5 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~) 8 8 Homepage: http://www.bitlbee.org/ 9 Vcs-Git: https://github.com/bitlbee/bitlbee 10 Vcs-Browser: https://github.com/bitlbee/bitlbee 9 Vcs-Bzr: http://code.bitlbee.org/bitlbee/ 11 10 12 11 Package: bitlbee … … 15 14 Conflicts: bitlbee-libpurple 16 15 Replaces: bitlbee-libpurple 17 Description: IRC to other chat networks gateway (default version)16 Description: An IRC to other chat networks gateway (default version) 18 17 This program can be used as an IRC server which forwards everything you 19 18 say to people on other chat networks: Jabber (which includes Google Talk … … 25 24 Conflicts: bitlbee 26 25 Replaces: bitlbee 27 Description: IRC to other chat networks gateway (using libpurple)26 Description: An IRC to other chat networks gateway (using libpurple) 28 27 This program can be used as an IRC server which forwards everything you 29 28 say to people on other chat networks: Jabber (which includes Google Talk … … 41 40 Depends: ${misc:Depends}, net-tools, adduser 42 41 Replaces: bitlbee 43 Description: IRC to other chat networks gateway (common files/docs)42 Description: An IRC to other chat networks gateway (common files/docs) 44 43 This program can be used as an IRC server which forwards everything you 45 44 say to people on other chat networks: Jabber (which includes Google Talk … … 52 51 Architecture: all 53 52 Depends: ${misc:Depends}, bitlbee (>= ${source:Version}) | bitlbee-libpurple (>= ${source:Version}), bitlbee (<< ${source:Version}.1~) | bitlbee-libpurple (<< ${source:Version}.1~), bitlbee-common (= ${source:Version}) 54 Description: IRC to other chat networks gateway (dev files)53 Description: An IRC to other chat networks gateway (dev files) 55 54 This program can be used as an IRC server which forwards everything you 56 55 say to people on other chat networks: Jabber (which includes Google Talk … … 62 61 Architecture: any 63 62 Depends: ${misc:Depends}, ${shlibs:Depends}, bitlbee (= ${binary:Version}) | bitlbee-libpurple (= ${binary:Version}), bitlbee-common (= ${source:Version}) 64 Description: IRC to other chat networks gateway (OTR plugin)63 Description: An IRC to other chat networks gateway (OTR plugin) 65 64 This program can be used as an IRC server which forwards everything you 66 65 say to people on other chat networks: Jabber (which includes Google Talk … … 74 73 Depends: ${misc:Depends}, ${shlibs:Depends}, bitlbee (= ${binary:Version}) | bitlbee-libpurple (= ${binary:Version}), bitlbee-common (= ${source:Version}) 75 74 Recommends: skyped 76 Description: IRC to other chat networks gateway (Skype plugin)75 Description: An IRC to other chat networks gateway (Skype plugin) 77 76 This program can be used as an IRC server which forwards everything you 78 77 say to people on other chat networks: Jabber (which includes Google Talk -
debian/rules
r537d9b9 rba52ac5 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 44 42 build: build-stamp 45 43 build-stamp: … … 74 72 dh_testdir 75 73 dh_testroot 76 dh_ prep74 dh_clean -k 77 75 dh_installdirs 78 76 … … 82 80 $(MAKE) -C debian/build-native install-plugin-otr DESTDIR=`pwd`/debian/bitlbee-plugin-otr 83 81 $(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-common87 endif88 82 89 83 ifneq ($(BITLBEE_SKYPE),0) … … 114 108 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 115 109 dh_installdebconf 116 ifeq ($(HAS_DH_SYSTEMD),1)117 dh_systemd_enable118 110 dh_installinit --init-script=bitlbee 119 dh_systemd_start120 else121 dh_installinit --init-script=bitlbee122 endif123 111 dh_installman 124 112 dh_lintian -
doc/CHANGES
r537d9b9 rba52ac5 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), given9 support by the IM protocols and your IRC client. See this for details:10 https://wiki.bitlbee.org/SelfMessages11 * IRCv3.1 support and part of 3.2: cap-3.2, sasl-3.2, multi-prefix,12 away-notify, extended-join, userhost-in-names13 * Send numeric errors when failing to join a channel, to not confuse clients14 * Channel autojoins should be more reliable now.15 - jabber:16 * Carbons (XEP-0280), for self-message support. It's not widely supported17 by most public XMPP servers (easier if you host your own), but this will18 probably change in the next few years. Thanks kormat for the original patch.19 * Fix typing notifications between two bitlbee users or with gtalk users20 * Remove facebook XMPP code, point people at bitlbee-facebook.21 * Show groupchat kick/ban/leave reasons22 * SASL ANONYMOUS (XEP-0175), for "guest" logins, see "help set anonymous"23 * Hipchat: 'chat add hipchat "channel name"' now tries to guess the JID24 - purple:25 * Fix problems remembering SSL certificates as trusted26 * Fix /join #channel, which joined a differently named channel27 * Fix crash when doing "chat with" with skypeweb28 * Fix html entities appearing in some protocols29 * Fix setting away states in jabber, which failed silently30 * 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 useful34 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 xmlconsole42 * A few minor fixes: color multiline messages, filter incoming color codes.43 - Packaging:44 * Show ./configure args in bitlbee -V, config.h and Makefile.settings45 * 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 channels49 * Fix all sorts of crashing bugs when cancelling in-progress connections.50 51 Finished 19 Mar 201652 5 53 6 Version 3.4.1: -
doc/user-guide/commands.xml
r537d9b9 rba52ac5 258 258 259 259 <para> 260 Available actions: add, with , list. See <emphasis>help chat <action></emphasis> for more information.260 Available actions: add, with. 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 |!index> [<channel>]</syntax>266 <syntax>chat add <account id> <room> [<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. ( <emphasis>channel <channel> set auto_join true</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. (See <emphasis>chat set</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>301 282 </bitlbee-command> 302 283 … … 307 288 <para> 308 289 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>313 290 </para> 314 291 </description> … … 668 645 <para> 669 646 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 priority688 647 </para> 689 648 </description> … … 1532 1491 and any modes they should have. The following statuses are currently 1533 1492 recognised: <emphasis>online</emphasis> (i.e. available, not 1534 away), <emphasis>special</emphasis> (specific to the protocol),1535 <emphasis>away</emphasis>,and <emphasis>offline</emphasis>.1493 away), <emphasis>special</emphasis>, <emphasis>away</emphasis>, 1494 and <emphasis>offline</emphasis>. 1536 1495 </para> 1537 1496 … … 1539 1498 If a status is followed by a valid channel mode character 1540 1499 (@, % or +), it will be given to users with that status. 1541 For example, <emphasis>online@,special%,away+,offline</emphasis> 1500 For example, <emphasis>online@,special%,away+,offline</emphasis> 1542 1501 will show all users in the channel. Online people will 1543 1502 have +o, people who are online but away will have +v, … … 1858 1817 </bitlbee-command> 1859 1818 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 1870 </bitlbee-command>1871 1872 1819 <bitlbee-command name="qlist"> 1873 1820 <short-description>List all the unanswered questions root asked</short-description> -
doc/user-guide/genhelp.py
r537d9b9 rba52ac5 65 65 66 66 # Actually normalize whitespace 67 if 'pre' not in tag.attrib: 68 tag.text = normalize(tag.text) 67 tag.text = normalize(tag.text) 69 68 tag.tail = normalize(tag.tail) 70 69 -
doc/user-guide/misc.xml
r537d9b9 rba52ac5 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 464 447 </chapter> -
init/bitlbee.service.in
r537d9b9 rba52ac5 5 5 [Service] 6 6 ExecStart=@sbindir@bitlbee -F -n 7 KillMode=process8 7 9 8 [Install] -
irc.h
r537d9b9 rba52ac5 29 29 #define IRC_MAX_LINE 512 30 30 #define IRC_MAX_ARGS 16 31 #define IRC_WORD_WRAP 42532 31 33 32 #define IRC_LOGIN_TIMEOUT 60 … … 93 92 logging in, this may contain a password we should 94 93 send to identify after USER/NICK are received. */ 95 char *auth_backend;96 94 97 95 char umode[8]; -
irc_cap.c
r537d9b9 rba52ac5 177 177 178 178 } else if (g_strcasecmp(cmd[1], "END") == 0) { 179 if (!(irc->status & USTATUS_CAP_PENDING)) {180 return;181 }182 179 irc->status &= ~USTATUS_CAP_PENDING; 183 180 -
irc_channel.c
r537d9b9 rba52ac5 245 245 ic->users = g_slist_insert_sorted(ic->users, icu, irc_channel_user_cmp); 246 246 247 if (iu == ic->irc->user || iu == ic->irc->root) { 248 irc_channel_update_ops(ic, set_getstr(&ic->irc->b->set, "ops")); 249 } 247 irc_channel_update_ops(ic, set_getstr(&ic->irc->b->set, "ops")); 250 248 251 249 if (iu == ic->irc->user || ic->flags & IRC_CHANNEL_JOINED) { -
irc_commands.c
r537d9b9 rba52ac5 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 = auth_check_pass(irc,user, pass);99 status = storage_check_pass(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 : ",770 PACKAGE, BITLBEE_VERSION, irc->root->host );769 irc_send_num(irc, 351, "%s-%s. %s :%s/%s ", 770 PACKAGE, BITLBEE_VERSION, irc->root->host, ARCH, CPU); 771 771 } 772 772 -
irc_im.c
r537d9b9 rba52ac5 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 122 128 if ((bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE)) { 123 129 if (bu->flags & BEE_USER_ONLINE) { … … 147 153 148 154 bee_irc_channel_update(irc, NULL, iu); 149 150 /* If away-notify enabled, send status updates when:151 * Away or Online state changes152 * Status changes (e.g. "Away" to "Mobile")153 * Status message changes154 */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 }162 155 163 156 return TRUE; … … 299 292 } 300 293 301 wrapped = word_wrap(msg, IRC_WORD_WRAP);294 wrapped = word_wrap(msg, 425); 302 295 irc_send_msg(src_iu, message_type, dst, wrapped, prefix); 303 296 g_free(wrapped); … … 349 342 } 350 343 351 static gboolean bee_irc_user_nick_update(irc_user_t *iu , gboolean offline_only);344 static gboolean bee_irc_user_nick_update(irc_user_t *iu); 352 345 353 346 static gboolean bee_irc_user_fullname(bee_t *bee, bee_user_t *bu) … … 377 370 } 378 371 379 bee_irc_user_nick_update(iu , TRUE);372 bee_irc_user_nick_update(iu); 380 373 381 374 return TRUE; … … 384 377 static gboolean bee_irc_user_nick_hint(bee_t *bee, bee_user_t *bu, const char *hint) 385 378 { 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); 379 bee_irc_user_nick_update((irc_user_t *) bu->ui_data); 394 380 395 381 return TRUE; … … 400 386 irc_user_t *iu = (irc_user_t *) bu->ui_data; 401 387 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 } 402 394 403 395 bee_irc_channel_update(irc, NULL, 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) 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) 410 407 { 411 408 bee_user_t *bu = iu->bu; 412 409 char *newnick; 413 410 414 if ( offline_only &&bu->flags & BEE_USER_ONLINE) {411 if (bu->flags & BEE_USER_ONLINE) { 415 412 /* Ignore if the user is visible already. */ 416 413 return TRUE; … … 435 432 { 436 433 bee_user_t *bu = iu->bu; 434 bee_user_flags_t online; 437 435 438 436 if (bu == FALSE) { … … 440 438 } 441 439 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 442 445 nick_del(bu); 443 bee_irc_user_nick_update(iu, FALSE); 444 446 bee_irc_user_nick_update(iu); 447 448 bu->flags |= online; 445 449 } 446 450 … … 457 461 } 458 462 459 if (iu->last_channel == NULL && 460 (away = irc_user_get_away(iu)) && 463 if ((away = irc_user_get_away(iu)) && 461 464 time(NULL) >= iu->away_reply_timeout) { 462 465 irc_send_num(iu->irc, 301, "%s :%s", iu->nick, away); … … 673 676 } 674 677 675 wrapped = word_wrap(msg, IRC_WORD_WRAP);678 wrapped = word_wrap(msg, 425); 676 679 irc_send_msg(iu, "PRIVMSG", ic->name, wrapped, ts); 677 680 g_free(ts); … … 1143 1146 1144 1147 bee_irc_log, 1145 bee_irc_user_nick_change,1146 1148 }; -
irc_send.c
r537d9b9 rba52ac5 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 .", irc->root->host,44 PACKAGE, BITLBEE_VERSION );43 irc_send_num(irc, 2, ":Host %s is running %s %s %s/%s.", irc->root->host, 44 PACKAGE, BITLBEE_VERSION, ARCH, CPU); 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;57 s ize_t len;58 59 g_file_get_contents(global.conf->motdfile, &motd, &len, NULL); 60 61 if ( !motd || !len) {56 char motd[2048]; 57 ssize_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) { 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'; 68 69 linebuf[79] = len = 0; 69 70 max = sizeof(linebuf) - 1; … … 100 101 } 101 102 102 g_free(motd); 103 103 if (fd != -1) { 104 close(fd); 105 } 104 106 } 105 107 … … 346 348 } 347 349 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 } 350 /* rfc1459 doesn't mention this: G means gone, H means here */ 351 status_prefix[0] = iu->flags & IRC_USER_AWAY ? 'G' : 'H'; 355 352 356 353 irc_send_num(irc, 352, "%s %s %s %s %s %s :0 %s", -
irc_user.c
r537d9b9 rba52ac5 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 );253 ctcp[0], PACKAGE " " BITLBEE_VERSION " " ARCH "/" CPU); 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
r537d9b9 rba52ac5 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 " \r\n"97 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" 98 98 "\r\n", url->file, url->host); 99 99 -
lib/misc.c
r537d9b9 rba52ac5 549 549 } 550 550 551 /* Word wrapping. Yes, I know this isn't UTF-8 clean. I'm willing to take the risk. */ 551 552 char *word_wrap(const char *msg, int line_len) 552 553 { … … 581 582 } 582 583 if (i == 0) { 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); 584 g_string_append_len(ret, msg, line_len); 591 585 g_string_append_c(ret, '\n'); 592 msg += l en;586 msg += line_len; 593 587 } 594 588 } … … 793 787 return string; 794 788 } 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' parameter798 * 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
r537d9b9 rba52ac5 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);154 153 155 154 #endif -
lib/proxy.c
r537d9b9 rba52ac5 87 87 } 88 88 89 /* calls phb->func safely by ensuring that the phb struct doesn't exist in the90 * 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 the101 * fd (still open), look it up in the hash table, get NULL, and102 * proceed to close the fd and do nothing else */103 func(data, source, B_EV_IO_READ);104 105 return FALSE;106 }107 108 89 static gboolean proxy_connected(gpointer data, gint source, b_input_condition cond) 109 90 { … … 144 125 phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ); 145 126 } else { 146 phb_connected(phb, source); 127 phb->func(phb->data, source, B_EV_IO_READ); 128 phb_free(phb, TRUE); 147 129 } 148 130 … … 240 222 if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || 241 223 (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { 242 return phb_connected(phb, source); 224 phb->func(phb->data, source, B_EV_IO_READ); 225 return phb_free(phb, TRUE); 243 226 } 244 227 … … 312 295 memset(packet, 0, sizeof(packet)); 313 296 if (read(source, packet, 9) >= 4 && packet[1] == 90) { 314 return phb_connected(phb, source); 297 phb->func(phb->data, source, B_EV_IO_READ); 298 return phb_free(phb, TRUE); 315 299 } 316 300 … … 400 384 } 401 385 402 return phb_connected(phb, source); 386 phb->func(phb->data, source, B_EV_IO_READ); 387 return phb_free(phb, TRUE); 403 388 } 404 389 -
lib/sha1.c
r537d9b9 rba52ac5 24 24 #define HMAC_BLOCK_SIZE 64 25 25 26 void b_hmac(GChecksumType checksum_type, const char *key_, size_t key_len, 27 const char *payload, size_t payload_len, guint8 **digest)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]) 28 28 { 29 GChecksum *checksum; 30 size_t hash_len; 31 guint8 *hash; 29 sha1_state_t sha1; 30 guint8 hash[SHA1_HASH_SIZE]; 32 31 guint8 key[HMAC_BLOCK_SIZE + 1]; 33 32 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);42 33 43 34 if (key_len == 0) { … … 52 43 memset(key, 0, HMAC_BLOCK_SIZE + 1); 53 44 if (key_len > HMAC_BLOCK_SIZE) { 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); 45 sha1_init(&sha1); 46 sha1_append(&sha1, (guint8 *) key_, key_len); 47 sha1_finish(&sha1, key); 58 48 } else { 59 49 memcpy(key, key_, key_len); … … 61 51 62 52 /* Inner part: H(K XOR 0x36, text) */ 63 checksum = g_checksum_new(checksum_type);53 sha1_init(&sha1); 64 54 for (i = 0; i < HMAC_BLOCK_SIZE; i++) { 65 55 key[i] ^= 0x36; 66 56 } 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); 57 sha1_append(&sha1, key, HMAC_BLOCK_SIZE); 58 sha1_append(&sha1, (const guint8 *) payload, payload_len); 59 sha1_finish(&sha1, hash); 71 60 72 61 /* Final result: H(K XOR 0x5C, inner stuff) */ 73 checksum = g_checksum_new(checksum_type);62 sha1_init(&sha1); 74 63 for (i = 0; i < HMAC_BLOCK_SIZE; i++) { 75 64 key[i] ^= 0x36 ^ 0x5c; 76 65 } 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); 66 sha1_append(&sha1, key, HMAC_BLOCK_SIZE); 67 sha1_append(&sha1, hash, SHA1_HASH_SIZE); 68 sha1_finish(&sha1, digest); 83 69 } 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 90 70 91 71 /* I think this follows the scheme described on: -
lib/ssl_gnutls.c
r537d9b9 rba52ac5 42 42 #include <limits.h> 43 43 44 #if defined(ULONG_MAX) && ULONG_MAX > 4294967295UL 45 #define GNUTLS_STUPID_CAST (long) 46 #else 47 #define GNUTLS_STUPID_CAST (int) 48 #endif 49 44 50 #define SSLDEBUG 0 45 51 … … 329 335 330 336 sock_make_nonblocking(conn->fd); 331 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) (long)conn->fd);337 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) GNUTLS_STUPID_CAST conn->fd); 332 338 333 339 ssl_cache_resume(conn); -
lib/ssl_openssl.c
r537d9b9 rba52ac5 67 67 SSL_library_init(); 68 68 69 meth = SSLv23_client_method();69 meth = TLSv1_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);72 71 73 72 initialized = TRUE; -
otr.c
r537d9b9 rba52ac5 268 268 } 269 269 270 #ifndef OTR_BI271 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 NULL280 };281 282 return &info;283 }284 #endif285 286 270 gboolean otr_irc_new(irc_t *irc) 287 271 { … … 429 413 430 414 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ 431 if (a->prpl->options & PRPL_OPT_NOOTR) {415 if (a->prpl->options & OPT_NOOTR) { 432 416 return 0; 433 417 } … … 457 441 458 442 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ 459 if (ic->acc->prpl->options & PRPL_OPT_NOOTR ||443 if (ic->acc->prpl->options & OPT_NOOTR || 460 444 iu->bu->flags & BEE_USER_NOOTR) { 461 445 return msg; … … 1400 1384 void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...) 1401 1385 { 1402 char *msg_, *msg;1403 1386 struct im_connection *ic = 1404 1387 check_imc(opdata, ctx->accountname, ctx->protocol); … … 1408 1391 1409 1392 va_start(va, fmt); 1410 msg_= g_strdup_vprintf(fmt, va);1393 char *msg = g_strdup_vprintf(fmt, va); 1411 1394 va_end(va); 1412 1413 msg = word_wrap(msg_, IRC_WORD_WRAP);1414 1395 1415 1396 if (u) { … … 1420 1401 } 1421 1402 1422 g_free(msg_);1423 1403 g_free(msg); 1424 1404 } -
protocols/account.c
r537d9b9 rba52ac5 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 | ACC_SET_LOCKABLE;65 s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD; 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 | ACC_SET_LOCKABLE;71 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 72 72 set_setstr(&a->set, "username", user); 73 73 -
protocols/account.h
r537d9b9 rba52ac5 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 */64 63 } account_set_flag_t; 65 64 … … 69 68 ACC_FLAG_HANDLE_DOMAINS = 0x04, /* Contact handles need a domain portion. */ 70 69 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) */72 70 } account_flag_t; 73 71 -
protocols/bee.h
r537d9b9 rba52ac5 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 91 86 /* This one's mostly used so save space and make it easier (cheaper) to 92 87 compare groups of contacts, etc. */ … … 136 131 137 132 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);139 133 } bee_ui_funcs_t; 140 134 … … 190 184 G_MODULE_EXPORT void imcb_chat_invite(struct im_connection *ic, const char *name, const char *who, const char *msg); 191 185 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 196 186 #endif /* __BEE_H__ */ -
protocols/bee_chat.c
r537d9b9 rba52ac5 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
r537d9b9 rba52ac5 31 31 bee_user_t *bu = bee_user_by_handle(bee, ic, handle); 32 32 33 if (bee->ui->ft_in_start && bu) {33 if (bee->ui->ft_in_start) { 34 34 return bee->ui->ft_in_start(bee, bu, file_name, file_size); 35 35 } else { -
protocols/jabber/conference.c
r537d9b9 rba52ac5 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, 31 gboolean always_use_nicks) 30 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password) 32 31 { 33 32 struct jabber_chat *jc; … … 58 57 g_free(jc); 59 58 return NULL; 60 }61 62 if (always_use_nicks) {63 jc->flags = JCFLAG_ALWAYS_USE_NICKS;64 59 } 65 60 … … 100 95 g_free(cserv); 101 96 102 c = jabber_chat_join(ic, rjid, jd->username, NULL , FALSE);97 c = jabber_chat_join(ic, rjid, jd->username, NULL); 103 98 g_free(rjid); 104 99 if (c == NULL) { … … 249 244 } 250 245 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 264 246 /* Not really the same syntax as the normal pkt_ functions, but this isn't 265 247 called by the xmltree parser directly and this way I can add some extra … … 346 328 *s = 0; /* Should NEVER be NULL, but who knows... */ 347 329 } 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 353 330 imcb_chat_add_buddy(chat, bud->ext_jid); 354 331 if (s) { … … 356 333 } 357 334 } else if (type) { /* type can only be NULL or "unavailable" in this function */ 358 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid && !jabber_chat_has_other_resources(ic, bud)) {335 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid) { 359 336 char *reason = NULL; 360 337 char *status = NULL; … … 466 443 467 444 if (subject && chat) { 468 char empty[1] = ""; 469 char *subject_text = subject->text_len > 0 ? subject->text : empty; 445 char *subject_text = subject->text_len > 0 ? subject->text : ""; 470 446 if (g_strcmp0(chat->topic, subject_text) != 0) { 471 447 bare_jid = (bud) ? jabber_get_bare_jid(bud->ext_jid) : NULL; … … 503 479 bare_jid = jabber_get_bare_jid(bud->ext_jid ? bud->ext_jid : bud->full_jid); 504 480 final_from = bare_jid; 505 if (bud == jc->me || (g_strcasecmp(final_from, ic->acc->user) == 0)) { 506 flags = OPT_SELFMESSAGE; 507 } 481 flags = (bud == jc->me) ? OPT_SELFMESSAGE : 0; 508 482 } else { 509 483 final_from = nick; -
protocols/jabber/iq.c
r537d9b9 rba52ac5 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)); 69 70 } else if (strcmp(s, XMLNS_TIME_OLD) == 0) { 70 71 time_t time_ep; … … 233 234 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 234 235 imc_logout(ic, FALSE); 235 return XT_ ABORT;236 return XT_HANDLED; 236 237 } 237 238 … … 286 287 imcb_log(ic, "Warning: Received incomplete IQ packet while authenticating"); 287 288 imc_logout(ic, FALSE); 288 return XT_ ABORT;289 return XT_HANDLED; 289 290 } 290 291 … … 1059 1060 return XT_HANDLED; 1060 1061 } 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
r537d9b9 rba52ac5 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 86 84 if (strcmp(acc->prpl->name, "hipchat") == 0) { 87 85 set_setstr(&acc->set, "server", "chat.hipchat.com"); 88 86 } 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 325 323 while (jd->filetransfers) { 326 324 imcb_file_canceled(ic, (( struct jabber_transfer *) jd->filetransfers->data)->ft, "Logging out"); … … 399 397 if (g_strcasecmp(who, JABBER_OAUTH_HANDLE) == 0 && 400 398 !(jd->flags & OPT_LOGGED_IN) && jd->fd == -1) { 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)) { 399 if (sasl_oauth2_get_refresh_token(ic, message)) { 406 400 return 1; 407 401 } else { … … 583 577 } else { 584 578 /* jabber_chat_join without the underscore is the conference.c one */ 585 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password"), 586 set_getbool(sets, "always_use_nicks")); 579 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password")); 587 580 } 588 581 … … 593 586 { 594 587 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 }610 588 } 611 589 … … 708 686 void jabber_chat_add_settings(account_t *acc, set_t **head) 709 687 { 710 set_add(head, "always_use_nicks", "false", set_eval_bool, NULL);711 712 688 /* Meh. Stupid room passwords. Not trying to obfuscate/hide 713 689 them from the user for now. */ … … 717 693 void jabber_chat_free_settings(account_t *acc, set_t **head) 718 694 { 719 set_del(head, "always_use_nicks");720 721 695 set_del(head, "password"); 722 696 } … … 785 759 ret->chat_join = jabber_chat_join_; 786 760 ret->chat_with = jabber_chat_with_; 787 ret->chat_list = jabber_chat_list_;788 761 ret->chat_add_settings = jabber_chat_add_settings; 789 762 ret->chat_free_settings = jabber_chat_free_settings; -
protocols/jabber/jabber.h
r537d9b9 rba52ac5 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,78 77 } jabber_chat_flags_t; 79 78 … … 263 262 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data); 264 263 int jabber_iq_disco_server(struct im_connection *ic); 265 int jabber_iq_disco_muc(struct im_connection *ic, const char *muc_server);266 264 267 265 /* si.c */ … … 341 339 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg); 342 340 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);344 341 345 342 extern const struct oauth2_service oauth2_service_google; 346 343 347 344 /* conference.c */ 348 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password, 349 gboolean always_use_nicks); 345 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password); 350 346 struct groupchat *jabber_chat_with(struct im_connection *ic, char *who); 351 347 struct groupchat *jabber_chat_by_jid(struct im_connection *ic, const char *name); -
protocols/jabber/jabber_util.c
r537d9b9 rba52ac5 315 315 int i; 316 316 317 if (!jid1 || !jid2) {318 return FALSE;319 }320 321 317 for (i = 0;; i++) { 322 318 if (jid1[i] == '\0' || jid1[i] == '/' || jid2[i] == '\0' || jid2[i] == '/') { -
protocols/jabber/message.c
r537d9b9 rba52ac5 27 27 { 28 28 struct im_connection *ic = data; 29 struct jabber_data *jd = ic->proto_data; 29 30 char *from = xt_find_attr(node, carbons_sent ? "to" : "from"); 30 31 char *type = xt_find_attr(node, "type"); … … 37 38 if (!from) { 38 39 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 } 39 51 } 40 52 -
protocols/jabber/presence.c
r537d9b9 rba52ac5 222 222 cap = xt_new_node("c", NULL, NULL); 223 223 xt_add_attr(cap, "xmlns", XMLNS_CAPS); 224 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/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 } 225 231 xt_add_attr(cap, "ver", BITLBEE_VERSION); /* The XEP wants this hashed, but nobody's doing that. */ 226 232 xt_add_child(node, cap); -
protocols/jabber/s5bytestream.c
r537d9b9 rba52ac5 928 928 proxy = next; 929 929 } 930 931 g_free(proxysetting);932 930 } 933 931 -
protocols/jabber/sasl.c
r537d9b9 rba52ac5 39 39 }; 40 40 41 /* """"""""""""""""""""""""""""""oauth"""""""""""""""""""""""""""""" */42 #define HIPCHAT_SO_CALLED_OAUTH_URL "https://hipchat.com/account/api"43 44 41 xt_status sasl_pkt_mechanisms(struct xt_node *node, gpointer data) 45 42 { … … 48 45 struct xt_node *c, *reply; 49 46 char *s; 50 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_anonymous = 0 , sup_hipchat_oauth = 0;47 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_anonymous = 0; 51 48 int want_oauth = FALSE, want_hipchat = FALSE, want_anonymous = FALSE; 52 49 GString *mechs; … … 83 80 } else if (c->text && g_strcasecmp(c->text, "X-OAUTH2") == 0) { 84 81 sup_gtalk = 1; 85 } else if (c->text && g_strcasecmp(c->text, "X-HIPCHAT-OAUTH2") == 0) {86 sup_hipchat_oauth = 1;87 82 } 88 83 … … 95 90 96 91 if (!want_oauth && !sup_plain && !sup_digest) { 97 if ( sup_gtalk || sup_hipchat_oauth) {92 if (!sup_gtalk) { 98 93 imcb_error(ic, "This server requires OAuth " 99 94 "(supported schemes:%s)", mechs->str); … … 115 110 } 116 111 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); 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); 144 126 reply->text_len = strlen(reply->text); 145 g_string_free(gs, TRUE); 146 127 g_free(s); 147 128 } else if (want_oauth) { 148 129 imcb_error(ic, "OAuth requested, but not supported by server"); … … 168 149 /* The rest will be done later, when we receive a <challenge/>. */ 169 150 } else if (sup_plain) { 151 int len; 170 152 GString *gs; 171 153 char *username; … … 192 174 } 193 175 194 reply->text = base64_encode((unsigned char *) gs->str, gs->len); 176 len = gs->len; 177 s = g_string_free(gs, FALSE); 178 179 reply->text = base64_encode((unsigned char *) s, len); 195 180 reply->text_len = strlen(reply->text); 196 g_ string_free(gs, TRUE);181 g_free(s); 197 182 } 198 183 … … 443 428 { 444 429 struct jabber_data *jd = ic->proto_data; 430 char *msg, *url; 445 431 446 432 imcb_log(ic, "Starting OAuth authentication"); … … 448 434 /* Temporary contact, just used to receive the OAuth response. */ 449 435 imcb_add_buddy(ic, JABBER_OAUTH_HANDLE, NULL); 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 } 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); 465 439 imcb_buddy_msg(ic, JABBER_OAUTH_HANDLE, "Respond to this message with the returned " 466 440 "authorization token.", 0, 0); 467 441 442 g_free(msg); 443 g_free(url); 468 444 } 469 445 … … 477 453 return FALSE; 478 454 } 455 456 static void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, 457 const char *error); 479 458 480 459 int sasl_oauth2_get_refresh_token(struct im_connection *ic, const char *msg) … … 507 486 } 508 487 509 void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error)488 static void sasl_oauth2_got_token(gpointer data, const char *access_token, const char *refresh_token, const char *error) 510 489 { 511 490 struct im_connection *ic = data; -
protocols/jabber/si.c
r537d9b9 rba52ac5 393 393 struct jabber_transfer *tf = NULL; 394 394 struct jabber_data *jd = ic->proto_data; 395 struct jabber_error *err;396 395 397 396 if (!(tgt_jid = xt_find_attr(node, "from")) || 398 !(ini_jid = xt_find_attr(node, "to")) || 399 !(iq_id = xt_find_attr(node, "id"))) { 397 !(ini_jid = xt_find_attr(node, "to"))) { 400 398 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);429 399 return XT_HANDLED; 430 400 } … … 439 409 * <value> 440 410 */ 441 if (!(c = xt_find_node(node->children, "si")) || 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")) || 442 415 !(cmp = xt_find_attr(c, "xmlns")) || 443 416 !(strcmp(cmp, XMLNS_SI) == 0) || … … 466 439 } 467 440 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 468 456 tf->ini_jid = g_strdup(ini_jid); 469 457 tf->tgt_jid = g_strdup(tgt_jid); -
protocols/nogaim.c
r537d9b9 rba52ac5 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 52 42 gboolean load_plugin(char *path) 53 43 { 54 GList *l;55 struct plugin_info *i;56 struct plugin_info *info;57 struct plugin_info * (*info_function) (void) = NULL;58 44 void (*init_function) (void); 59 45 60 46 GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY); 61 gboolean loaded = FALSE;62 47 63 48 if (!mod) { 64 log_message(LOGLVL_ERROR, " Error loading plugin `%s': %s\n", path, g_module_error());49 log_message(LOGLVL_ERROR, "Can't find `%s', not loading (%s)\n", path, g_module_error()); 65 50 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);106 51 } 107 52 108 53 if (!g_module_symbol(mod, "init_plugin", (gpointer *) &init_function)) { 109 54 log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path); 110 g_module_close(mod);111 55 return FALSE; 112 56 } 113 57 114 if (info_function) {115 plugins = g_list_insert_sorted_with_data(plugins, info,116 pluginscmp, NULL);117 }118 119 58 init_function(); 59 120 60 return TRUE; 121 61 } … … 133 73 134 74 while ((entry = g_dir_read_name(dir))) { 135 if (!g_str_has_suffix(entry, "." G_MODULE_SUFFIX)) {136 continue;137 }138 139 75 path = g_build_filename(global.conf->plugindir, entry, NULL); 140 76 if (!path) { … … 150 86 g_dir_close(dir); 151 87 } 152 }153 154 GList *get_plugins()155 {156 return plugins;157 88 } 158 89 #endif … … 237 168 load_plugins(); 238 169 #endif 239 }240 241 GList *get_protocols()242 {243 return protocols;244 }245 246 GList *get_protocols_disabled()247 {248 return disabled_protocols;249 170 } 250 171 … … 574 495 } 575 496 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) 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) 578 500 { 579 501 bee_t *bee = ic->bee; … … 587 509 bu->nick = g_strdup(nick); 588 510 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) { 511 if (bee->ui->user_nick_hint) { 592 512 bee->ui->user_nick_hint(bee, bu, nick); 593 513 } 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);606 514 } 607 515 … … 759 667 if (away && *away) { 760 668 GList *m = ic->acc->prpl->away_states(ic); 761 if (m == NULL) {762 return 0;763 }764 669 msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL; 765 670 away = imc_away_state_find(m, away, &msg) ? : -
protocols/nogaim.h
r537d9b9 rba52ac5 102 102 103 103 GSList *groupchats; 104 GSList *chatlist;105 104 }; 106 105 … … 145 144 char *description; 146 145 }; 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 PurpleProtocolOptions152 * enum for convenience, but there's no promise of direct compatibility with153 * those values. As of libpurple 2.8.0 they use up to 0x800 (1 << 11), which is154 * a nice coincidence.155 */156 typedef enum {157 /* The protocol doesn't use passwords158 * 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 them162 * 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;168 146 169 147 struct prpl { … … 291 269 gboolean (* handle_is_self) (struct im_connection *, const char *who); 292 270 293 /* This sets/updates the im_connection->chatlist field with a294 * bee_chat_info_t GSList. This function should ensure the295 * bee_chat_list_finish() function gets called at some point296 * after the chat list is completely updated.297 */298 void (* chat_list) (struct im_connection *, const char *server);299 300 271 /* Some placeholders so eventually older plugins may cooperate with newer BitlBees. */ 301 272 void *resv1; … … 306 277 }; 307 278 308 struct plugin_info309 {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_PLUGINS319 G_MODULE_EXPORT GList *get_plugins();320 #endif321 322 279 /* im_api core stuff. */ 323 280 void nogaim_init(); 324 G_MODULE_EXPORT GList *get_protocols();325 G_MODULE_EXPORT GList *get_protocols_disabled();326 281 G_MODULE_EXPORT GSList *get_connections(); 327 282 G_MODULE_EXPORT struct prpl *find_protocol(const char *name); … … 375 330 G_MODULE_EXPORT void imcb_rename_buddy(struct im_connection *ic, const char *handle, const char *realname); 376 331 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);378 332 G_MODULE_EXPORT void imcb_buddy_action_response(bee_user_t *bu, const char *action, char * const args[], void *data); 379 333 G_MODULE_EXPORT GSList *imcb_get_local_contacts(struct im_connection *ic); -
protocols/oscar/conn.c
r537d9b9 rba52ac5 383 383 { 384 384 aim_conn_t *connstruct; 385 guint16 port = AIM_LOGIN_PORT; 386 char *host; 387 int i; 385 388 386 389 if (!(connstruct = aim_conn_getnext(sess))) { … … 397 400 } 398 401 399 /* The code that used to be here was very broken */ 400 g_return_val_if_reached(connstruct); 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); 401 425 402 426 return connstruct; -
protocols/purple/bpurple.h
r537d9b9 rba52ac5 13 13 GHashTable *input_requests; 14 14 guint next_request_id; 15 char *chat_list_server;16 GSList *filetransfers;17 15 }; 18 16 -
protocols/purple/ft.c
r537d9b9 rba52ac5 42 42 char *fn, *handle; 43 43 gboolean ui_wants_data; 44 int timeout;45 44 }; 46 45 … … 65 64 struct prpl_xfer_data *px = ft->data; 66 65 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); 66 purple_xfer_request_denied(px->xfer); 99 67 } 100 68 101 69 static void prplcb_xfer_new(PurpleXfer *xfer) 102 70 { 103 purple_xfer_ref(xfer);104 105 71 if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) { 106 72 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 107 struct purple_data *pd;108 73 109 74 xfer->ui_data = px; … … 113 78 px->ic = purple_ic_by_pa(xfer->account); 114 79 115 pd = px->ic->proto_data;116 pd->filetransfers = g_slist_prepend(pd->filetransfers, px);117 118 80 purple_xfer_set_local_filename(xfer, px->fn); 119 81 … … 150 112 px->ft->accept = prpl_xfer_accept; 151 113 px->ft->canceled = prpl_xfer_canceled; 152 px->ft->free = prpl_xfer_free;153 114 px->ft->write_request = prpl_xfer_write_request; 154 115 … … 203 164 204 165 166 /* Generic (IM<>UI): */ 205 167 static void prplcb_xfer_destroy(PurpleXfer *xfer) 206 168 { 207 169 struct prpl_xfer_data *px = xfer->ui_data; 208 170 209 if (px) { 210 px->xfer = NULL; 211 } 171 g_free(px->fn); 172 g_free(px->handle); 173 if (px->fd >= 0) { 174 close(px->fd); 175 } 176 g_free(px); 212 177 } 213 178 … … 259 224 struct prpl_xfer_data *px = xfer->ui_data; 260 225 261 if (px && px->ft) {226 if (px->ft) { 262 227 imcb_file_canceled(px->ic, px->ft, "Canceled by remote end"); 263 } else if (px){228 } else { 264 229 /* px->ft == NULL for sends, because of the two stages. :-/ */ 265 230 imcb_error(px->ic, "File transfer cancelled by remote end"); … … 275 240 { 276 241 struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); 277 struct purple_data *pd;278 242 char *dir, *basename; 279 243 280 244 ft->data = px; 281 245 px->ft = ft; 282 px->ft->free = prpl_xfer_free;283 246 284 247 dir = g_strdup("/tmp/bitlbee-purple-ft.XXXXXX"); … … 309 272 px->handle = g_strdup(handle); 310 273 311 pd = px->ic->proto_data;312 pd->filetransfers = g_slist_prepend(pd->filetransfers, px);313 314 274 imcb_log(ic, 315 275 "Due to libpurple limitations, the file has to be cached locally before proceeding with the actual file transfer. Please wait..."); 316 276 317 px->timeout =b_timeout_add(0, purple_transfer_request_cb, ft);277 b_timeout_add(0, purple_transfer_request_cb, ft); 318 278 } 319 279 … … 335 295 struct prpl_xfer_data *px = ft->data; 336 296 337 px->timeout = 0;338 339 297 if (ft->write == NULL) { 340 298 ft->write = prpl_xfer_write; … … 364 322 px->ft = NULL; 365 323 } else { 366 px->timeout =b_timeout_add(0, purple_transfer_request_cb, ft);324 b_timeout_add(0, purple_transfer_request_cb, ft); 367 325 } 368 326 369 327 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 }385 328 } 386 329 -
protocols/purple/purple.c
r537d9b9 rba52ac5 43 43 const char *message, const char *who); 44 44 45 void purple_transfer_cancel_all(struct im_connection *ic);46 47 45 /* purple_request_input specific stuff */ 48 46 typedef void (*ri_callback_t)(gpointer, const gchar *); … … 56 54 }; 57 55 58 struct purple_roomlist_data {59 GSList *chats;60 gint topic;61 gboolean initialized;62 };63 64 65 56 struct im_connection *purple_ic_by_pa(PurpleAccount *pa) 66 57 { … … 103 94 } 104 95 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 116 96 static void purple_init(account_t *acc) 117 97 { 118 char *prpl_id = purple_get_account_prpl_id(acc); 119 PurplePlugin *prpl = purple_plugins_find_with_id(prpl_id); 98 PurplePlugin *prpl = purple_plugins_find_with_id((char *) acc->prpl->data); 120 99 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 121 100 PurpleAccount *pa; … … 283 262 /* Go through all away states to figure out if away/status messages 284 263 are possible. */ 285 pa = purple_account_new(acc->user, prpl_id);264 pa = purple_account_new(acc->user, (char *) acc->prpl->data); 286 265 for (st = purple_account_get_status_types(pa); st; st = st->next) { 287 266 PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data); … … 366 345 367 346 ic->proto_data = pd = g_new0(struct purple_data, 1); 368 pd->account = purple_account_new(acc->user, purple_get_account_prpl_id(acc));347 pd->account = purple_account_new(acc->user, (char *) acc->prpl->data); 369 348 pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal, 370 349 NULL, g_free); … … 392 371 } 393 372 394 if (pd->filetransfers) {395 purple_transfer_cancel_all(ic);396 }397 398 373 purple_account_set_enabled(pd->account, "BitlBee", FALSE); 399 374 purple_connections = g_slist_remove(purple_connections, ic); 400 375 purple_accounts_remove(pd->account); 401 imcb_chat_list_free(ic);402 g_free(pd->chat_list_server);403 376 g_hash_table_destroy(pd->input_requests); 404 377 g_free(pd); … … 700 673 } 701 674 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 717 675 void purple_chat_kick(struct groupchat *gc, char *who, const char *message) 718 676 { … … 739 697 GHashTable *chat_hash; 740 698 PurpleConversation *conv; 741 struct groupchat *gc;742 699 GList *info, *l; 743 700 … … 773 730 g_list_free(info); 774 731 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 778 732 serv_join_chat(purple_account_get_connection(pd->account), chat_hash); 779 733 780 734 g_hash_table_destroy(chat_hash); 781 735 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 } 736 return imcb_chat_new(ic, room); 808 737 } 809 738 … … 1041 970 1042 971 /* Generic handler for IM or chat messages, covers write_chat, write_im and write_conv */ 1043 static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message _, guint32 bee_flags, time_t mtime)972 static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message, guint32 bee_flags, time_t mtime) 1044 973 { 1045 974 struct im_connection *ic = purple_ic_by_pa(conv->account); 1046 975 struct groupchat *gc = conv->ui_data; 1047 char *message = g_strdup(message_);1048 976 PurpleBuddy *buddy; 1049 977 … … 1054 982 1055 983 if (conv->type == PURPLE_CONV_TYPE_IM) { 1056 imcb_buddy_msg(ic, who,message, bee_flags, mtime);984 imcb_buddy_msg(ic, (char *) who, (char *) message, bee_flags, mtime); 1057 985 } else if (gc) { 1058 imcb_chat_msg(gc, who, message, bee_flags, mtime); 1059 } 1060 1061 g_free(message); 986 imcb_chat_msg(gc, who, (char *) message, bee_flags, mtime); 987 } 1062 988 } 1063 989 … … 1245 1171 struct im_connection *ic = purple_ic_by_pa(account); 1246 1172 struct purple_data *pd = ic->proto_data; 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); 1173 struct request_input_data *ri = g_new0(struct request_input_data, 1); 1174 guint id = pd->next_request_id++; 1260 1175 1261 1176 ri->id = id; … … 1267 1182 1268 1183 imcb_add_buddy(ic, ri->buddy, NULL); 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 } 1184 imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0); 1281 1185 1282 1186 return ri; … … 1352 1256 prplcb_privacy_deny_added, /* deny_added */ 1353 1257 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 */1458 1258 }; 1459 1259 … … 1622 1422 purple_request_set_ui_ops(&bee_request_uiops); 1623 1423 purple_privacy_set_ui_ops(&bee_privacy_uiops); 1624 purple_roomlist_set_ui_ops(&bee_roomlist_uiops);1625 1424 purple_notify_set_ui_ops(&bee_notify_uiops); 1626 1425 purple_accounts_set_ui_ops(&bee_account_uiops); … … 1639 1438 char *dir; 1640 1439 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 1647 1440 g_assert((int) B_EV_IO_READ == (int) PURPLE_INPUT_READ); 1648 1441 g_assert((int) B_EV_IO_WRITE == (int) PURPLE_INPUT_WRITE); … … 1650 1443 dir = g_strdup_printf("%s/purple", global.conf->configdir); 1651 1444 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);1656 1445 g_free(dir); 1657 1446 … … 1717 1506 funcs.chat_with = purple_chat_with; 1718 1507 funcs.chat_invite = purple_chat_invite; 1719 funcs.chat_topic = purple_chat_set_topic;1720 1508 funcs.chat_kick = purple_chat_kick; 1721 1509 funcs.chat_leave = purple_chat_leave; 1722 1510 funcs.chat_join = purple_chat_join; 1723 funcs.chat_list = purple_chat_list;1724 1511 funcs.transfer_request = purple_transfer_request; 1725 1512 … … 1730 1517 for (prots = purple_plugins_get_protocols(); prots; prots = prots->next) { 1731 1518 PurplePlugin *prot = prots->data; 1732 PurplePluginProtocolInfo *pi = prot->info->extra_info;1733 1519 struct prpl *ret; 1734 1520 … … 1744 1530 ret->name += 5; 1745 1531 } 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 1755 1532 register_protocol(ret); 1756 1533 … … 1762 1539 ret = g_memdup(&funcs, sizeof(funcs)); 1763 1540 ret->name = "oscar"; 1764 /* purple_get_account_prpl_id() determines the actual protocol ID (icq/aim) */ 1765 ret->data = NULL; 1541 ret->data = prot->info->id; 1766 1542 register_protocol(ret); 1767 1543 } -
protocols/skype/skype.c
r537d9b9 rba52ac5 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 NULL1775 };1776 1777 return &info;1778 } -
protocols/twitter/twitter.c
r537d9b9 rba52ac5 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);349 347 } else { 350 348 twitter_main_loop_start(ic); … … 471 469 g_regex_match(regex, msg, 0, &match_info); 472 470 while (g_match_info_matches(match_info)) { 473 gchar * url;471 gchar *s, *url; 474 472 475 473 url = g_match_info_fetch(match_info, 2); 476 474 url_len_diff += target_len - g_utf8_strlen(url, -1); 477 475 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 } 478 481 g_free(url); 479 482 g_match_info_next(match_info, NULL); … … 538 541 if (strcmp(acc->prpl->name, "twitter") == 0) { 539 542 def_url = TWITTER_API_URL; 540 def_tul = "2 3";543 def_tul = "22"; 541 544 def_mentions = "true"; 542 545 } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ … … 687 690 } 688 691 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 695 692 http_close(td->stream); 696 693 twitter_filter_remove_all(ic); … … 951 948 } else if ((g_strcasecmp(cmd[0], "favourite") == 0 || 952 949 g_strcasecmp(cmd[0], "favorite") == 0 || 953 g_strcasecmp(cmd[0], "fav") == 0 || 954 g_strcasecmp(cmd[0], "like") == 0) && cmd[1]) { 950 g_strcasecmp(cmd[0], "fav") == 0) && cmd[1]) { 955 951 if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) { 956 952 twitter_favourite_tweet(ic, id); … … 964 960 } else if (g_strcasecmp(cmd[0], "unfollow") == 0 && cmd[1]) { 965 961 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);972 962 goto eof; 973 963 } else if ((g_strcasecmp(cmd[0], "report") == 0 || … … 1092 1082 struct prpl *ret = g_new0(struct prpl, 1); 1093 1083 1094 ret->options = PRPL_OPT_NOOTR | PRPL_OPT_NO_PASSWORD;1084 ret->options = OPT_NOOTR; 1095 1085 ret->name = "twitter"; 1096 1086 ret->login = twitter_login; … … 1119 1109 ret = g_memdup(ret, sizeof(struct prpl)); 1120 1110 ret->name = "identica"; 1121 ret->options = PRPL_OPT_NOOTR;1122 1111 register_protocol(ret); 1123 1112 } -
protocols/twitter/twitter.h
r537d9b9 rba52ac5 61 61 62 62 GSList *follow_ids; 63 GSList *mutes_ids;64 GSList *noretweets_ids;65 63 GSList *filters; 66 64 -
protocols/twitter/twitter_http.c
r537d9b9 rba52ac5 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 " \r\n",81 "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n", 82 82 is_post ? "POST" : "GET", 83 83 base_url ? base_url->file : td->url_path, -
protocols/twitter/twitter_lib.c
r537d9b9 rba52ac5 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);249 247 250 248 /** … … 259 257 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 260 258 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);289 259 290 260 g_free(args[1]); … … 364 334 twitter_get_users_lookup(ic); 365 335 } 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 active382 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 response402 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 active427 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 ids447 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;460 336 461 337 txl->list = NULL; … … 591 467 #endif 592 468 593 static void expand_entities(char **text, const JSON_Object *node , const JSON_Object *extended_node);469 static void expand_entities(char **text, const JSON_Object *node); 594 470 595 471 /** … … 603 479 static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node) 604 480 { 605 struct twitter_xml_status *txs = {0};481 struct twitter_xml_status *txs; 606 482 const JSON_Object *rt = NULL; 607 const JSON_Value *text_value = NULL;608 const JSON_Object *extended_node = NULL;609 483 610 484 if (!node) { … … 614 488 615 489 JSON_O_FOREACH(node, k, v) { 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); 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); 623 493 } else if (strcmp("retweeted_status", k) == 0 && (rt = json_object(v))) { 624 494 // Handling below. … … 646 516 struct twitter_xml_status *rtxs = twitter_xt_get_status(rt); 647 517 if (rtxs) { 518 g_free(txs->text); 648 519 txs->text = g_strdup_printf("RT @%s: %s", rtxs->user->screen_name, rtxs->text); 649 520 txs->id = rtxs->id; 650 521 txs_free(rtxs); 651 522 } 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); 523 } else { 524 expand_entities(&txs->text, node); 656 525 } 657 526 … … 695 564 } 696 565 697 expand_entities(&txs->text, node , NULL);566 expand_entities(&txs->text, node); 698 567 699 568 if (txs->text && txs->user && txs->id) { … … 705 574 } 706 575 707 static void expand_entities(char **text, const JSON_Object *node , const JSON_Object *extended_node)708 { 709 JSON_Object *entities, * extended_entities, *quoted;576 static void expand_entities(char **text, const JSON_Object *node) 577 { 578 JSON_Object *entities, *quoted; 710 579 char *quote_url = NULL, *quote_text = NULL; 711 580 … … 725 594 } 726 595 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 734 596 JSON_O_FOREACH(entities, k, v) { 735 597 int i; … … 975 837 struct twitter_data *td = ic->proto_data; 976 838 char *last_id_str; 977 char *uid_str;978 839 979 840 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);992 841 return; 993 842 } … … 1014 863 set_setstr(&ic->acc->set, "_last_tweet", last_id_str); 1015 864 g_free(last_id_str); 1016 g_free(uid_str);1017 865 } 1018 866 … … 1032 880 } 1033 881 882 ic->flags |= OPT_PONGED; 1034 883 td = ic->proto_data; 1035 884 … … 1047 896 imc_logout(ic, TRUE); 1048 897 return; 1049 }1050 1051 if (req == td->stream) {1052 ic->flags |= OPT_PONGED;1053 898 } 1054 899 … … 1154 999 JSON_Object *target = json_object_get_object(o, "target"); 1155 1000 const char *type = json_object_get_string(o, "event"); 1156 struct twitter_xml_user *us = NULL;1157 struct twitter_xml_user *ut = NULL;1158 1001 1159 1002 if (!type || !source || !target) { … … 1162 1005 1163 1006 if (strcmp(type, "follow") == 0) { 1164 us = twitter_xt_get_user(source);1165 ut = twitter_xt_get_user(target);1007 struct twitter_xml_user *us = twitter_xt_get_user(source); 1008 struct twitter_xml_user *ut = twitter_xt_get_user(target); 1166 1009 if (g_strcasecmp(us->screen_name, td->user) == 0) { 1167 1010 twitter_add_buddy(ic, ut->screen_name, ut->name); 1168 1011 } 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); 1012 txu_free(us); 1013 txu_free(ut); 1014 } 1204 1015 1205 1016 return TRUE; … … 1498 1309 td->flags &= ~TWITTER_GOT_TIMELINE; 1499 1310 1500 char *args[ 8];1311 char *args[6]; 1501 1312 args[0] = "cursor"; 1502 1313 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); 1503 1314 args[2] = "include_entities"; 1504 1315 args[3] = "true"; 1505 args[4] = "tweet_mode";1506 args[5] = "extended";1507 1316 if (td->timeline_id) { 1508 args[ 6] = "since_id";1509 args[ 7] = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id);1317 args[4] = "since_id"; 1318 args[5] = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id); 1510 1319 } 1511 1320 1512 1321 if (twitter_http(ic, TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, args, 1513 td->timeline_id ? 8 : 6) == NULL) {1322 td->timeline_id ? 6 : 4) == NULL) { 1514 1323 if (++td->http_fails >= 5) { 1515 1324 imcb_error(ic, "Could not retrieve %s: %s", … … 1522 1331 g_free(args[1]); 1523 1332 if (td->timeline_id) { 1524 g_free(args[ 7]);1333 g_free(args[5]); 1525 1334 } 1526 1335 } … … 1537 1346 td->flags &= ~TWITTER_GOT_MENTIONS; 1538 1347 1539 char *args[ 8];1348 char *args[6]; 1540 1349 args[0] = "cursor"; 1541 1350 args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); … … 1549 1358 args[5] = g_strdup_printf("%d", set_getint(&ic->acc->set, "show_old_mentions")); 1550 1359 } 1551 args[6] = "tweet_mode";1552 args[7] = "extended";1553 1360 1554 1361 if (twitter_http(ic, TWITTER_MENTIONS_URL, twitter_http_get_mentions, 1555 ic, 0, args, 8) == NULL) {1362 ic, 0, args, 6) == NULL) { 1556 1363 if (++td->http_fails >= 5) { 1557 1364 imcb_error(ic, "Could not retrieve %s: %s", … … 1722 1529 } 1723 1530 1724 /**1725 * Mute or unmute a user1726 */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 1737 1531 void twitter_status_destroy(struct im_connection *ic, guint64 id) 1738 1532 { -
protocols/twitter/twitter_lib.h
r537d9b9 rba52ac5 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"67 65 68 66 /* Account URLs */ … … 78 76 #define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/" 79 77 80 /* Mute URLs */81 #define TWITTER_MUTES_CREATE_URL "/mutes/users/create.json"82 #define TWITTER_MUTES_DESTROY_URL "/mutes/users/destroy.json"83 84 78 /* Report spam */ 85 79 #define TWITTER_REPORT_SPAM_URL "/users/report_spam.json" … … 93 87 gboolean twitter_get_timeline(struct im_connection *ic, gint64 next_cursor); 94 88 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);97 89 void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor); 98 90 … … 100 92 void twitter_direct_messages_new(struct im_connection *ic, char *who, char *message); 101 93 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);103 94 void twitter_status_destroy(struct im_connection *ic, guint64 id); 104 95 void twitter_status_retweet(struct im_connection *ic, guint64 id); -
root_commands.c
r537d9b9 rba52ac5 143 143 } 144 144 145 status = auth_check_pass(irc, irc->user->nick, password); 146 if (load && (status == STORAGE_OK)) { 145 if (load) { 147 146 status = storage_load(irc, password); 147 } else { 148 status = storage_check_pass(irc->user->nick, password); 148 149 } 149 150 … … 158 159 irc_rootmsg(irc, "Password accepted%s", 159 160 load ? ", settings and accounts loaded" : ""); 161 irc_setpass(irc, password); 160 162 irc->status |= USTATUS_IDENTIFIED; 161 163 irc_umode_set(irc, "+R", 1); … … 266 268 storage_status_t status; 267 269 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 270 status = storage_remove(irc->user->nick, cmd[1]); 273 271 switch (status) { 274 272 case STORAGE_NO_SUCH_USER: … … 342 340 int st; 343 341 344 if (s && s->flags & SET_LOCKED) {345 irc_rootmsg(irc, "This setting can not be changed");346 return 0;347 }348 342 if (s && checkflags && checkflags(irc, s) == 0) { 349 343 return 0; … … 394 388 irc_rootmsg(irc, "This setting can only be changed when the account is %s-line", "on"); 395 389 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;399 390 } 400 391 … … 418 409 419 410 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 }425 411 426 412 if (cmd[4] == NULL) { … … 470 456 irc_rootmsg(irc, "No need to enter a password for this " 471 457 "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);479 458 } else { 480 459 irc_rootmsg(irc, "You can now use the /OPER command to " … … 486 465 } 487 466 } 488 } else if (prpl->options & PRPL_OPT_NO_PASSWORD) {489 irc_rootmsg(irc, "Note: this account doesn't use password for login");490 467 } 491 468 … … 576 553 577 554 if (len >= 1 && g_strncasecmp(cmd[2], "del", len) == 0) { 578 if (a->flags & ACC_FLAG_LOCKED) { 579 irc_rootmsg(irc, "Account is locked, can't delete"); 580 } 581 else if (a->ic) { 555 if (a->ic) { 582 556 irc_rootmsg(irc, "Account is still logged in, can't delete"); 583 557 } else { … … 1134 1108 } 1135 1109 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_PLUGINS1178 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 #endif1201 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 1221 1110 static void cmd_qlist(irc_t *irc, char **cmd) 1222 1111 { … … 1245 1134 1246 1135 if (g_strcasecmp(cmd[1], "add") == 0) { 1247 bee_chat_info_t *ci; 1248 char *channel, *room, *s; 1136 char *channel, *s; 1249 1137 struct irc_channel *ic; 1250 guint i;1251 1138 1252 1139 MIN_ARGS(3); … … 1260 1147 } 1261 1148 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 1284 1149 if (cmd[4] == NULL) { 1285 channel = g_strdup( room);1150 channel = g_strdup(cmd[3]); 1286 1151 if ((s = strchr(channel, '@'))) { 1287 1152 *s = 0; … … 1303 1168 set_setstr(&ic->set, "chat_type", "room") && 1304 1169 set_setstr(&ic->set, "account", cmd[2]) && 1305 set_setstr(&ic->set, "room", room)) {1170 set_setstr(&ic->set, "room", cmd[3])) { 1306 1171 irc_rootmsg(irc, "Chatroom successfully added."); 1307 1172 } else { … … 1313 1178 } 1314 1179 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]);1330 1180 } else if (g_strcasecmp(cmd[1], "with") == 0) { 1331 1181 irc_user_t *iu; … … 1342 1192 irc_rootmsg(irc, "Can't open a groupchat with %s.", cmd[2]); 1343 1193 } 1344 } else if (g_strcasecmp(cmd[1], "set") == 0 || 1194 } else if (g_strcasecmp(cmd[1], "list") == 0 || 1195 g_strcasecmp(cmd[1], "set") == 0 || 1345 1196 g_strcasecmp(cmd[1], "del") == 0) { 1346 1197 irc_rootmsg(irc, … … 1352 1203 cmd[1]); 1353 1204 } 1354 }1355 1356 /* some arbitrary numbers */1357 #define CHAT_TITLE_LEN_MIN 201358 #define CHAT_TITLE_LEN_MAX 1001359 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);1412 1205 } 1413 1206 … … 1463 1256 { 1464 1257 GSList *files = irc->file_transfers; 1465 GSList *next;1466 1258 1467 1259 enum { LIST, REJECT, CANCEL }; … … 1481 1273 } 1482 1274 1483 for (; files; files = next) { 1484 next = files->next; 1275 for (; files; files = g_slist_next(files)) { 1485 1276 file_transfer_t *file = files->data; 1486 1277 … … 1566 1357 { "nick", 1, cmd_nick, 0 }, 1567 1358 { "no", 0, cmd_yesno, 0 }, 1568 { "plugins", 0, cmd_plugins, 0 },1569 1359 { "qlist", 0, cmd_qlist, 0 }, 1570 1360 { "register", 0, cmd_register, 0 }, -
set.h
r537d9b9 rba52ac5 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 */52 51 } set_flags_t; 53 52 -
storage.c
r537d9b9 rba52ac5 29 29 #include "bitlbee.h" 30 30 31 extern storage_t storage_text; 31 32 extern storage_t storage_xml; 32 33 … … 91 92 } 92 93 93 storage_status_t storage_check_pass( irc_t *irc,const char *nick, const char *password)94 storage_status_t storage_check_pass(const char *nick, const char *password) 94 95 { 95 96 GList *gl; … … 101 102 storage_status_t status; 102 103 103 status = st->check_pass( irc,nick, password);104 status = st->check_pass(nick, password); 104 105 if (status != STORAGE_NO_SUCH_USER) { 105 106 return status; … … 175 176 } 176 177 177 storage_status_t storage_remove(const char *nick )178 storage_status_t storage_remove(const char *nick, const char *password) 178 179 { 179 180 GList *gl; … … 189 190 storage_status_t status; 190 191 191 status = st->remove(nick );192 status = st->remove(nick, password); 192 193 ok |= status == STORAGE_OK; 193 194 if (status != STORAGE_NO_SUCH_USER && status != STORAGE_OK) { -
storage.h
r537d9b9 rba52ac5 31 31 STORAGE_NO_SUCH_USER, 32 32 STORAGE_INVALID_PASSWORD, 33 STORAGE_CHECK_BACKEND,34 33 STORAGE_ALREADY_EXISTS, 35 34 STORAGE_OTHER_ERROR /* Error that isn't caused by user input, such as … … 44 43 void (*init)(void); 45 44 46 storage_status_t (*check_pass)( irc_t *irc,const char *nick, const char *password);45 storage_status_t (*check_pass)(const char *nick, const char *password); 47 46 48 47 storage_status_t (*load)(irc_t *irc, const char *password); 49 48 storage_status_t (*save)(irc_t *irc, int overwrite); 50 storage_status_t (*remove)(const char *nick );49 storage_status_t (*remove)(const char *nick, const char *password); 51 50 52 51 /* May be NULL if not supported by backend */ … … 54 53 } storage_t; 55 54 56 storage_status_t storage_check_pass( irc_t *irc,const char *nick, const char *password);55 storage_status_t storage_check_pass(const char *nick, const char *password); 57 56 58 57 storage_status_t storage_load(irc_t * irc, const char *password); 59 58 storage_status_t storage_save(irc_t *irc, char *password, int overwrite); 60 storage_status_t storage_remove(const char *nick );59 storage_status_t storage_remove(const char *nick, const char *password); 61 60 62 61 void register_storage_backend(storage_t *); -
storage_xml.c
r537d9b9 rba52ac5 34 34 35 35 typedef enum { 36 XML_PASS_CHECK = 0, 37 XML_LOAD 38 } xml_action; 36 XML_PASS_CHECK_ONLY = -1, 37 XML_PASS_UNKNOWN = 0, 38 XML_PASS_WRONG, 39 XML_PASS_OK 40 } xml_pass_st; 39 41 40 42 /* To make it easier later when extending the format: */ … … 63 65 { 64 66 struct xt_node *c; 65 struct set *s;66 67 67 68 for (c = node->children; (c = xt_find_node(c, "setting")); c = c->next) { 68 69 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 }88 82 } 89 83 } … … 111 105 { 112 106 struct xml_parsedata *xd = data; 113 char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag , *locked;107 char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag; 114 108 char *pass_b64 = NULL; 115 109 unsigned char *pass_cr = NULL; … … 124 118 autoconnect = xt_find_attr(node, "autoconnect"); 125 119 tag = xt_find_attr(node, "tag"); 126 locked = xt_find_attr(node, "locked");127 120 128 121 protocol = xt_find_attr(node, "protocol"); … … 137 130 if (!handle || !pass_b64 || !protocol || !prpl) { 138 131 return XT_ABORT; 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); 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 } 144 149 } else { 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; 150 g_free(pass_cr); 151 g_free(password); 152 return XT_ABORT; 170 153 } 171 154 … … 227 210 }; 228 211 229 static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_ actionaction)212 static storage_status_t xml_load_real(irc_t *irc, const char *my_nick, const char *password, xml_pass_st action) 230 213 { 231 214 struct xml_parsedata xd[1]; … … 269 252 } 270 253 271 if (action == XML_PASS_CHECK){254 { 272 255 char *nick = xt_find_attr(node, "nick"); 273 256 char *pass = xt_find_attr(node, "password"); 274 char *backend = xt_find_attr(node, "auth_backend"); 275 276 if (!nick || !(pass || backend)) { 257 258 if (!nick || !pass) { 277 259 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;284 260 } else if ((st = md5_verify_password(xd->given_pass, pass)) != 0) { 285 261 ret = STORAGE_INVALID_PASSWORD; 286 } else { 287 ret = STORAGE_OK; 288 } 289 goto error; 290 } 291 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! */ 292 272 if (xt_handle(xp, NULL, 1) == XT_HANDLED) { 293 273 ret = STORAGE_OK; … … 304 284 static storage_status_t xml_load(irc_t *irc, const char *password) 305 285 { 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);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); 312 292 } 313 293 … … 324 304 struct xt_node *root, *cur; 325 305 306 /* Generate a salted md5sum of the password. Use 5 bytes for the salt 307 (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 326 317 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 salt331 (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 344 318 xt_add_attr(cur, "nick", irc->user->nick); 319 xt_add_attr(cur, "password", pass_buf); 345 320 xt_add_attr(cur, "version", XML_FORMAT_VERSION); 321 322 g_free(pass_buf); 346 323 347 324 xml_generate_settings(cur, &irc->b->set); … … 354 331 int pass_len; 355 332 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 } 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); 366 336 367 337 cur = xt_new_node("account", NULL, NULL); … … 378 348 xt_add_attr(cur, "server", acc->server); 379 349 } 380 if (acc->flags & ACC_FLAG_LOCKED) {381 xt_add_attr(cur, "locked", "true");382 }383 350 384 351 g_free(pass_b64); … … 425 392 xt_add_child(cur, xset = xt_new_node("setting", set->value, NULL)); 426 393 xt_add_attr(xset, "name", set->key); 427 if (set->flags & SET_LOCKED) {428 xt_add_attr(xset, "locked", "true");429 }430 394 } 431 395 } … … 486 450 487 451 488 static storage_status_t xml_remove(const char *nick )452 static storage_status_t xml_remove(const char *nick, const char *password) 489 453 { 490 454 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 } 491 461 492 462 lc = g_strdup(nick); -
tests/Makefile
r537d9b9 rba52ac5 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_OBJS) auth.o $(AUTH_OBJS)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.o 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
r537d9b9 rba52ac5 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));107 105 } 108 106 -
tests/check_util.c
r537d9b9 rba52ac5 137 137 5, 138 138 "aaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\na", 139 },140 {141 "áááááááááá",142 11,143 "ááááá\nááááá",144 139 }, 145 140 { -
unix.c
r537d9b9 rba52ac5 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 90 82 b_main_init(); 91 83 … … 112 104 } 113 105 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 120 106 if (global.conf->runmode == RUNMODE_INETD) { 107 log_link(LOGLVL_ERROR, LOGOUTPUT_IRC); 108 log_link(LOGLVL_WARNING, LOGOUTPUT_IRC); 109 121 110 i = bitlbee_inetd_init(); 122 111 log_message(LOGLVL_INFO, "%s %s starting in inetd mode.", PACKAGE, BITLBEE_VERSION); 123 112 124 113 } else if (global.conf->runmode == RUNMODE_DAEMON) { 114 log_link(LOGLVL_ERROR, LOGOUTPUT_CONSOLE); 115 log_link(LOGLVL_WARNING, LOGOUTPUT_CONSOLE); 116 125 117 i = bitlbee_daemon_init(); 126 118 log_message(LOGLVL_INFO, "%s %s starting in daemon mode.", PACKAGE, BITLBEE_VERSION); 127 119 } else if (global.conf->runmode == RUNMODE_FORKDAEMON) { 120 log_link(LOGLVL_ERROR, LOGOUTPUT_CONSOLE); 121 log_link(LOGLVL_WARNING, LOGOUTPUT_CONSOLE); 122 128 123 /* In case the operator requests a restart, we need this. */ 129 124 old_cwd = g_malloc(256);
Note: See TracChangeset
for help on using the changeset viewer.