# HG changeset patch # User Marcus Lundblad # Date 1303762385 0 # Node ID 974722699032036d14046061d07c904c728c99b9 # Parent d1315b4e1e4a4428f6f2577726e7b2650e311f9a# Parent a92f4cb593a4298246a395012f85709ed70b9f91 merge of 'a8f0eef7e999fe67029a8df6e8a41d9a1c564388' and 'fc93ce764b1029c91f84961e1b909a8d267e225e' diff -r a92f4cb593a4 -r 974722699032 .mtn-ignore --- a/.mtn-ignore Wed Feb 02 23:26:42 2011 +0000 +++ b/.mtn-ignore Mon Apr 25 20:13:05 2011 +0000 @@ -1,8 +1,8 @@ +(.*/)?TAGS$ (.*/)?\.svn +.*/?.*\.pc$ .*/?Makefile(\.in)?$ .*/?Makefile\.am\.mingw$ -(.*/)?TAGS$ -.*/?.*\.pc$ .*/perl/common/[^/]+\.c$ .*/perl/common/blib.* .*/perl/common/pm_to_blib$ @@ -11,8 +11,9 @@ .*\.dll$ .*\.exe$ .*\.loT$ -intltool-.* Doxyfile(\.mingw)?$ +VERSION$ +\.tx aclocal.m4 autogen.args compile @@ -24,42 +25,15 @@ config.status config.sub configure$ +depcomp +doc/finch.1$ +doc/html +doc/pidgin.1$ finch/finch$ finch/libgnt/gntmarshal.c finch/libgnt/gntmarshal.h -depcomp -doc/finch.1$ -doc/pidgin.1$ -doc/html -package_revision.h -package_revision_raw.txt -pidgin.apspec$ -pidgin.desktop$ -pidgin.spec$ -pidgin-.*.tar.gz -pidgin-.*.tar.bz2 -pidgin-*.*.*-dbgsym$ -pidgin-*.*.*-dbgsym.zip$ -pidgin-*.*.*-win32bin$ -pidgin-*.*.*-win32-bin.zip$ -pidgin/pidgin$ -pidgin/pixmaps/emotes/default/24/theme -pidgin/pixmaps/emotes/none/theme -pidgin/pixmaps/emotes/small/16/theme -pidgin/plugins/musicmessaging/music-messaging-bindings.c -pidgin/plugins/perl/common/Makefile.PL$ -pidgin/plugins/perl/common/Makefile.old -pidgin/win32/pidgin_dll_rc.rc$ -pidgin/win32/pidgin_exe_rc.rc$ -pidgin/win32/nsis/gtk-runtime-*.*.*.*.zip -pidgin/win32/nsis/gtk_runtime_stage$ -pidgin/win32/nsis/pidgin-translations.nsh$ -pidgin/win32/nsis/langmacros.nsh -pidgin/win32/nsis/nsis_translations.desktop -pidgin/win32/nsis/pidgin-spellcheck-preselect.nsh -pidgin/win32/nsis/pidgin-spellcheck.nsh -pidgin/win32/nsis/translations install-sh +intltool-.* libpurple/dbus-bindings.c libpurple/dbus-signals.c libpurple/dbus-types.c @@ -73,10 +47,10 @@ libpurple/plugins/perl/common/const-c.inc libpurple/plugins/perl/common/const-xs.inc libpurple/plugins/perl/common/lib -libpurple/purple.h$ libpurple/purple-client-bindings.c libpurple/purple-client-bindings.h libpurple/purple-client-example +libpurple/purple.h$ libpurple/tests/check_libpurple libpurple/tests/libpurple.. libpurple/version.h$ @@ -86,6 +60,34 @@ ltmain.sh missing mkinstalldirs +package_revision.h +package_revision_raw.txt +pidgin-*.*.*-dbgsym$ +pidgin-*.*.*-dbgsym.zip$ +pidgin-*.*.*-win32-bin.zip$ +pidgin-*.*.*-win32bin$ +pidgin-.*.tar.bz2 +pidgin-.*.tar.gz +pidgin.apspec$ +pidgin.desktop$ +pidgin.spec$ +pidgin/pidgin$ +pidgin/pixmaps/emotes/default/24/theme +pidgin/pixmaps/emotes/none/theme +pidgin/pixmaps/emotes/small/16/theme +pidgin/plugins/musicmessaging/music-messaging-bindings.c +pidgin/plugins/perl/common/Makefile.PL$ +pidgin/plugins/perl/common/Makefile.old +pidgin/win32/nsis/gtk-runtime-*.*.*.*.zip +pidgin/win32/nsis/gtk_runtime_stage$ +pidgin/win32/nsis/langmacros.nsh +pidgin/win32/nsis/nsis_translations.desktop +pidgin/win32/nsis/pidgin-spellcheck-preselect.nsh +pidgin/win32/nsis/pidgin-spellcheck.nsh +pidgin/win32/nsis/pidgin-translations.nsh$ +pidgin/win32/nsis/translations +pidgin/win32/pidgin_dll_rc.rc$ +pidgin/win32/pidgin_exe_rc.rc$ po/Makefile.in.in po/POTFILES$ po/missing @@ -94,4 +96,3 @@ po/stamp-it stamp-h1 win32-install-dir(\.release)? -VERSION$ diff -r a92f4cb593a4 -r 974722699032 COPYRIGHT --- a/COPYRIGHT Wed Feb 02 23:26:42 2011 +0000 +++ b/COPYRIGHT Mon Apr 25 20:13:05 2011 +0000 @@ -49,6 +49,7 @@ Carlos Bederian Dave Bell Igor Belyi +David Benjamin Brian Bernas Paul Betts Runa Bhattacharjee @@ -98,6 +99,7 @@ Markos Chandras Matthew Chapman Christophe Chapuis +Tirtha Chatterjee Patrick Cheung Ka-Hing Cheung Sadrul Habib Chowdhury @@ -185,6 +187,7 @@ Ignacy Gawedzki Georgi Georgiev Brian Geppert +Emanuele Giaquinta Thomas Gibson-Robinson Ike Gingerich Gustavo Giráldez @@ -281,6 +284,7 @@ Joe LaPenna Steve Láposi Daniel Larsson +Julia Lawall Peter Lawler Vadim Lebedev Ho-seok Lee @@ -318,6 +322,7 @@ Lalo Martins John Matthews Simo Mattila +Robert Matusewicz Michal Matyska Ryan McCabe Peter McCurdy @@ -390,6 +395,7 @@ Sebastián E. Peyrott Amitakhya Phukan Andrea Piccinelli +Mateusz Piękos Celso Pinto Joao Luís Marques Pinto Aleksander Piotrowski @@ -398,6 +404,7 @@ Eric Polino Ari Pollak Stephen Pope +Cristi Posoiu Nathan Poznick Jory A. Pratt David Preece @@ -414,6 +421,7 @@ Etan Reisner David Reiss Luoh Ren-Shan +Noa Resare Daniele Ricci Kristian Rietveld Pekka Riikonen @@ -546,6 +554,7 @@ Jorge Villaseñor (Masca) Bjoern Voigt Peter Volkov +Marius Wachtler Wan Hing Wah Philip Walford Nathan Walp diff -r a92f4cb593a4 -r 974722699032 ChangeLog --- a/ChangeLog Wed Feb 02 23:26:42 2011 +0000 +++ b/ChangeLog Mon Apr 25 20:13:05 2011 +0000 @@ -1,6 +1,80 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -version 2.7.10 (??/??/????): +version 2.8.0 (??/??/????): + General: + * Implement simple silence suppression for voice calls, preventing wasted + bandwidth for silent periods during a call. (Jakub Adam) (half of #13180) + + Gadu-Gadu: + * Allow showing your status only to buddies. (Mateusz Piękos) (#13358) + + libpurple: + * media: Allow obtaining active local and remote candidates. (#11830) + * media: Allow getting/setting video capabilities. (Jakub Adam) (half of + #13095) + * Simple Silence Suppression is optional per-account. (Jakub Adam) (half + of #13180) + * Fix purple-url-handler being unable to find an account. + + Pidgin: + * Duplicate code cleanup. (Gabriel Schulhof) (#10599) + + Windows-Specific Changes: + * Fix building libpurple with Visual C++ .NET 2005. This was accidentally + broken in 2.7.11. (Florian Quèze) + +version 2.7.11 (03/10/2011): + General: + * Our bundled libgadu should now build on HP-UX. + * Fix some instances of file transfers never completing. (Cristi Posoiu) + (#12472) + + Pidgin: + * Sort by Status no longer causes buddies to move around when you + click them. + * Fix embedding in the system tray on older GTK+ releases (such as on + CentOS 5.5 and older Fedora). + * No longer require libstartup-notification for startup notification + support. GTK+ has included support for years, so use it instead. (David + Benjamin) (#13245) + + AIM: + * Fix a bug where some buddies from your buddy list might not show up. + Affected non-English ICQ users the most. (#13386) + * Send keepalives for all types of network connections. Will hopefully + make chat rooms more reliable. (#1449) + + MSN: + * Fix bug that prevented added buddies to your buddy list in certain + circumstances. (#13298) + + MXit: + * MXit plugin and reported client version now follow the libpurple + version. + * Don't try to request profile information for non-user contacts. + * Allow Re-Invite for contacts in Deleted or Rejected state. + * Ensure we don't send packets too fast to the MXit server and trigger + its flood-detection mechanism. Also increased the internal packet queue + to 32 packets. + + XMPP: + * Fix building on platforms with an older glib (inadvertantly broken in + 2.7.10). (#13329) + * Don't treat the on-join status storms as 'new arrivals'. (Thijs + Alkemade) (#a14527) + * Extend the /join command to support room JIDs, enabling you to join + a room on any server. (Solarius, Matěj Cepl, Tirtha 'wyuka' + Chatterjee) (#4526) + * Add support for receiving a limited amount of history when joining a + room (not currently supported by Pidgin and Finch). (Thijs Alkemade) + (#10986, #a14219) + + Yahoo!/Yahoo! JAPAN: + * Fix CVE-2011-1091, denials of service caused by NULL pointer + dereferences due to improper handling of malformed YMSG packets. Thanks + to Marius Wachtler for reporting this and reviewing the fix! + +version 2.7.10 (02/06/2011): General: * Force video sources to all have the same capabilities. This reduces the number of times video must be scaled down, saving CPU time. (Jakub Adam) @@ -32,6 +106,10 @@ Samstag) (#13073) * Fixed bugs in purple_str_to_time() that caused the most recent 'make check' failures. (Nader Morshed) (#13131) + * Correct an issue that caused some UIs other than Pidgin or Finch to + leave a buddy in the "is typing" state. (Jan Kaluza) + * Fix potential information disclosure issues in the Cipher code. (Julia + Lawall) Pidgin: * Support using the Page Up and Page Down keys on the numeric keypad in @@ -61,7 +139,8 @@ * Handle Connection: Close headers for BOSH, when the server does not terminate the connection itself. (#13008) * Improved parsing for DIGEST-MD5, which should resolve issues - connecting to some jabberd2 servers. (#a14514) + connecting to some jabberd2 servers. This corrects an issue parsing + one-character or empty elements. (Noa Resare) (#a14514) Yahoo!/Yahoo! JAPAN: * Fix a crash when an account disconnects before a p2p session is @@ -300,6 +379,40 @@ * Bonjour support now requires Apple Bonjour Print Services version 2.0.0 or newer (http://support.apple.com/kb/dl999). + libpurple: + * Fall back to an ordinary request if a UI does not support showing a + request with an icon. Fixes receiving MSN file transfer requests + including a thumbnail in Finch. + + Pidgin: + * Add support for the Gadu-Gadu protocol in the gevolution plugin to + provide Evolution integration with contacts with GG IDs. (#10709) + * Remap the "Set User Mood" shortcut to Control-D, which does not + conflict with the previous shortcut for Get Buddy Info on the + selected buddy. + * Add a plugin action menu (under Tools) for the Voice and Video + Settings plugin. + + Finch: + * Add support for drop-down account options (like the SILC cipher + and HMAC options or the QQ protocol version). + + XMPP: + * Unify the connection security-related settings into one dropdown. + * Fix a crash when multiple accounts are simultaneously performing + SASL authentication when built with Cyrus SASL support. (thanks + to Jan Kaluza) (#11560) + * Restore the ability to connect to XMPP servers that do not offer + Stream ID. (#12331) + * Added support for using Google's relay servers when making voice and + video calls to Google clients. + + Yahoo/Yahoo JAPAN: + * Stop doing unnecessary lookups of certain alias information. This + solves deadlocks when a given Yahoo account has a ridiculously large + (>500 buddies) list and may improve login speed for those on slow + connections. (#12532) + version 2.7.3 (08/10/2010): General: * Use silent build rules for automake >1.11. You can enable verbose diff -r a92f4cb593a4 -r 974722699032 ChangeLog.API --- a/ChangeLog.API Wed Feb 02 23:26:42 2011 +0000 +++ b/ChangeLog.API Mon Apr 25 20:13:05 2011 +0000 @@ -1,6 +1,50 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -version 2.7.9 (??/??/????): +version 2.8.0 (??/??/????): + libpurple: + Added: + * account-authorization-requested-with-message signal (Stefan Ott) + (#8690) + * purple_account_add_buddy_with_invite + * purple_account_add_buddies_with_invite + * purple_notify_user_info_add_pair_plaintext + * purple_media_get_active_local_candidates + * purple_media_get_active_remote_candidates + * purple_media_manager_get_video_caps (Jakub Adam) (#13095) + * purple_media_manager_set_video_caps (Jakub Adam) (#13095) + * Added add_buddy_with_invite to PurplePluginProtocolInfo + * Added add_buddies_with_invite to PurplePluginProtocolInfo + + Deprecated: + * purple_account_add_buddy + * purple_account_add_buddies_with_invite + * add_buddy from PurplePluginProtocolInfo struct + * add_buddies from PurplePluginProtocolInfo struct + + Pidgin: + Added: + * pidgin_make_scrollable (Gabriel Schulhof) (#10599) + +version 2.7.11 (03/10/2011): + * libpurple: + Added: + * Four entries in the GHashTable passed when joining + an XMPP chat room which allow the UI to request a limited + amount of history. See XEP-0045 7.1.16 for details; the + entries are named history_maxchars, history_maxstanzas, + history_seconds, and history_since. history_since must be + interpretable by purple_str_to_time, and the prpl takes care + of formatting the time properly. + * Perl: + Added: + * Purple::find_conversation_with_account + * Purple::Conversation::Chat::send_with_flags + * Purple::Conversation::IM::send_with_flags + +version 2.7.10 (02/06/2011): + * No changes + +version 2.7.9 (12/26/2010): * No changes version 2.7.8 (12/19/2010): diff -r a92f4cb593a4 -r 974722699032 Doxyfile.in --- a/Doxyfile.in Wed Feb 02 23:26:42 2011 +0000 +++ b/Doxyfile.in Mon Apr 25 20:13:05 2011 +0000 @@ -1,4 +1,4 @@ -# Doxyfile 1.5.3 +# Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project @@ -14,175 +14,169 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of -# possible encodings. +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = @PACKAGE@ -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, -# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the # path to strip. -STRIP_FROM_PATH = +STRIP_FROM_PATH = -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = "signal=- @ref " \ @@ -195,25 +189,49 @@ "endsignals= " \ "constreturn=@note The return value of this function must not be modified or freed. @return " -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO @@ -223,266 +241,352 @@ CPP_CLI_SUPPORT = NO -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file +# If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = YES -# If this flag is set to YES, the members of anonymous namespaces will be extracted -# and appear in the documentation as a namespace called 'anonymous_namespace{file}', -# where file will be replaced with the base name of the file that contains the anonymous -# namespace. By default anonymous namespace are hidden. +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the +# Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = YES -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES -# The ENABLED_SECTIONS tag can be used to enable conditional +# The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. -ENABLED_SECTIONS = +ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = YES -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated +# The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = YES -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text " -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @top_srcdir@/libpurple \ @@ -491,104 +595,109 @@ @top_srcdir@/pidgin \ @top_srcdir@/doc -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. -# See http://www.gnu.org/software/libiconv for the list of possible encodings. +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. INPUT_ENCODING = UTF-8 -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.h \ *.dox -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = libpurple/purple-client.h \ libpurple/purple-client-bindings.h -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, -# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left # blank all files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = +IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be # ignored. -INPUT_FILTER = +INPUT_FILTER = -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. -FILTER_PATTERNS = +FILTER_PATTERNS = -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO @@ -597,34 +706,32 @@ # configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH -# then you must also enable this option. If you don't then doxygen will produce -# a warning and turn it on anyway +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES -# Setting the INLINE_SOURCES tag to YES will include the body +# Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES @@ -632,20 +739,21 @@ # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. +# link to the source code. +# Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES @@ -654,21 +762,21 @@ # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 3 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = Purple \ @@ -679,264 +787,465 @@ # configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = @top_srcdir@/doc/TracHeader.html -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = @top_srcdir@/doc/TracFooter.html -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! -HTML_STYLESHEET = +HTML_STYLESHEET = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = YES -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be # written to the html output directory. -CHM_FILE = +CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. -HHC_LOCATION = +HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members +# The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = YES -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO -# This tag can be used to set the number of enum values (range [1..20]) +# This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = YES -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. LATEX_CMD_NAME = latex -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. -EXTRA_PACKAGES = +EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! -LATEX_HEADER = +LATEX_HEADER = -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = -# Set optional variables used in the generation of an rtf document. +# Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man -# The MAN_EXTENSION tag determines the extension that is added to +# The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO @@ -945,33 +1254,33 @@ # configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = YES -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_SCHEMA = +XML_SCHEMA = -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_DTD = +XML_DTD = -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES @@ -980,10 +1289,10 @@ # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO @@ -992,319 +1301,346 @@ # configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- -# Configuration options related to the preprocessor +# Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- -# Configuration::additions related to external references +# Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen +# If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = -# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES -# The PERL_PATH should be the absolute path and name of the perl script +# The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to -# be found in the default search path. +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. -MSCGEN_PATH = +MSCGEN_PATH = -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @enable_dot@ -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES -# If set to YES, the inheritance and collaboration graphs will show the +# If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES -# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. CALL_GRAPH = YES -# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png -# The tag DOT_PATH can be used to specify the path where the dot tool can be +# The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. -DOT_PATH = +DOT_PATH = -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the # \dotfile command). -DOTFILE_DIRS = +DOTFILE_DIRS = -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the number -# of direct children of the root node in a graph is already larger than -# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 2 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = YES diff -r a92f4cb593a4 -r 974722699032 NEWS --- a/NEWS Wed Feb 02 23:26:42 2011 +0000 +++ b/NEWS Mon Apr 25 20:13:05 2011 +0000 @@ -2,7 +2,18 @@ Our development blog is available at: http://planet.pidgin.im -2.7.10 (??/??/????): +2.8.0 (??/??/????): + +2.7.11 (03/10/2011): + John: Yet another release. This time around we finally fixed that + annoying MSN buddy adding problem and a security issue in Yahoo. You + know the drill--upgrade already! + +2.7.10 (02/06/2011): + John: It's release time again. This release contains a bunch of stuff + committed from Trac. This is another "thank a patch writer" release. + Unfortunately, no one has fixed our wonderful MSN issues yet. There is + a tiny security fix in this release, as well. 2.7.9 (12/26/2010): John: Just a quick release for a security fix here. Elliott has not diff -r a92f4cb593a4 -r 974722699032 configure.ac --- a/configure.ac Wed Feb 02 23:26:42 2011 +0000 +++ b/configure.ac Mon Apr 25 20:13:05 2011 +0000 @@ -43,10 +43,10 @@ # # Make sure to update finch/libgnt/configure.ac with libgnt version changes. # -m4_define([purple_lt_current], [7]) +m4_define([purple_lt_current], [8]) m4_define([purple_major_version], [2]) -m4_define([purple_minor_version], [7]) -m4_define([purple_micro_version], [10]) +m4_define([purple_minor_version], [8]) +m4_define([purple_micro_version], [0]) m4_define([purple_version_suffix], [devel]) m4_define([purple_version], [purple_major_version.purple_minor_version.purple_micro_version]) @@ -55,7 +55,7 @@ m4_define([gnt_lt_current], [8]) m4_define([gnt_major_version], [2]) m4_define([gnt_minor_version], [8]) -m4_define([gnt_micro_version], [6]) +m4_define([gnt_micro_version], [8]) m4_define([gnt_version_suffix], [devel]) m4_define([gnt_version], [gnt_major_version.gnt_minor_version.gnt_micro_version]) @@ -263,6 +263,31 @@ AC_MSG_RESULT(no) ]) +# before gettexting, in case iconv matters +case "$host_os" in +darwin*) + AC_CHECK_LIB(resolv, res_query) + + AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h, [ + AC_CHECK_HEADER(IOKit/IOKitLib.h, [ + AC_DEFINE(HAVE_IOKIT, 1, [Define if we have IOKit]) + LIBS="$LIBS -framework IOKit -framework CoreFoundation" + ], []) + ], []) + + AC_MSG_CHECKING([for fink]) + if test -d /sw; then + AC_MSG_RESULT([found, adding /sw to search paths]) + CPPFLAGS="$CPPFLAGS -I/sw/include" + LDFLAGS="$LDFLAGS -L/sw/lib" + else + AC_MSG_RESULT([not found]) + fi + ;; +*) + ;; +esac + dnl ####################################################################### dnl # Disable creation and installation of translation files dnl ####################################################################### @@ -273,32 +298,6 @@ GETTEXT_PACKAGE=pidgin AC_SUBST(GETTEXT_PACKAGE) - - # before gettexting, in case iconv matters - case "$host_os" in - darwin*) - AC_CHECK_LIB(resolv, res_query) - - AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h, [ - AC_CHECK_HEADER(IOKit/IOKitLib.h, [ - AC_DEFINE(HAVE_IOKIT, 1, [Define if we have IOKit]) - LIBS="$LIBS -framework IOKit -framework CoreFoundation" - ], []) - ], []) - - AC_MSG_CHECKING([for fink]) - if test -d /sw; then - AC_MSG_RESULT([found, adding /sw to search paths]) - CPPFLAGS="$CPPFLAGS -I/sw/include" - LDFLAGS="$LDFLAGS -L/sw/lib" - else - AC_MSG_RESULT([not found]) - fi - ;; - *) - ;; - esac - ALL_LINGUAS="af am ar az be@latin bg bn bn_IN bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es et eu fa fi fr ga gl gu he hi hu hy id it ja ka km kn ko ku lo lt mai mhr mk mn mr ms_MY my_MM nb ne nl nn oc or pa pl pt_BR pt ps ro ru si sk sl sq sr sr@latin sv sw ta te th tr uk ur vi xh zh_CN zh_HK zh_TW" AM_GLIB_GNU_GETTEXT @@ -416,7 +415,7 @@ fi if test "x$enable_gtkui" = "xyes" ; then - PKG_CHECK_MODULES(GTK, [gtk+-3.0 >= 2.91.6], , [ + PKG_CHECK_MODULES(GTK, [gtk+-3.0 >= 3.0.0], , [ AC_MSG_RESULT(no) AC_MSG_ERROR([ @@ -541,27 +540,6 @@ fi dnl ####################################################################### - dnl # Check for startup notification - dnl ####################################################################### - if test "x$enable_startup_notification" = "xyes"; then - PKG_CHECK_MODULES(STARTUP_NOTIFICATION, [libstartup-notification-1.0 >= 0.5], , [ - AC_MSG_RESULT(no) - enable_startup_notification="no" - if test "x$force_deps" = "xyes" ; then - AC_MSG_ERROR([ -Startup notification development headers not found. -Use --disable-startup-notification if you do not need it. -]) - fi]) - - if test "x$enable_startup_notification" = "xyes"; then - AC_DEFINE(HAVE_STARTUP_NOTIFICATION, 1, [Define if we're using libstartup-notification.]) - AC_SUBST(STARTUP_NOTIFICATION_CFLAGS) - AC_SUBST(STARTUP_NOTIFICATION_LIBS) - fi - fi - - dnl ####################################################################### dnl # Check for GtkSpell dnl ####################################################################### if test "x$enable_gtkspell" = "xyes" ; then @@ -2575,6 +2553,7 @@ pidgin/plugins/perl/Makefile pidgin/plugins/perl/common/Makefile.PL pidgin/plugins/ticker/Makefile + libpurple/ciphers/Makefile libpurple/example/Makefile libpurple/gconf/Makefile libpurple/purple.pc diff -r a92f4cb593a4 -r 974722699032 doc/account-signals.dox --- a/doc/account-signals.dox Wed Feb 02 23:26:42 2011 +0000 +++ b/doc/account-signals.dox Mon Apr 25 20:13:05 2011 +0000 @@ -14,6 +14,7 @@ @signal account-actions-changed @signal account-alias-changed @signal account-authorization-requested + @signal account-authorization-requested-with-message @signal account-authorization-denied @signal account-authorization-granted @signal account-error-changed @@ -158,6 +159,23 @@ @since 2.3.0 @endsignaldef + @signaldef account-authorization-requested-with-message + @signalproto +int (*account_authorization_requested)(PurpleAccount *account, const char *user, const char *message); + @endsignalproto + @signaldesc + Emitted when a user requests authorization. + @param account The account. + @param user The name of the user requesting authorization. + @param message The authorization request message + @return PURPLE_ACCOUNT_RESPONSE_IGNORE to silently ignore the request, + PURPLE_ACCOUNT_RESPONSE_DENY to block the request (the sender might + get informed, PURPLE_ACCOUNT_RESPONSE_ACCEPT if the request should be + granted. If PURPLE_ACCOUNT_RESPONSE_PASS is returned, then the user + will be prompted with the request. + @since 2.8.0 + @endsignaldef + @signaldef account-authorization-denied @signalproto void (*account_authorization_denied)(PurpleAccount *account, const char *user); diff -r a92f4cb593a4 -r 974722699032 finch/gntblist.c --- a/finch/gntblist.c Wed Feb 02 23:26:42 2011 +0000 +++ b/finch/gntblist.c Mon Apr 25 20:13:05 2011 +0000 @@ -626,6 +626,7 @@ const char *username = purple_request_fields_get_string(allfields, "screenname"); const char *alias = purple_request_fields_get_string(allfields, "alias"); const char *group = purple_request_fields_get_string(allfields, "group"); + const char *invite = purple_request_fields_get_string(allfields, "invite"); PurpleAccount *account = purple_request_fields_get_account(allfields, "account"); const char *error = NULL; PurpleGroup *grp; @@ -662,7 +663,7 @@ purple_blist_add_buddy(buddy, NULL, grp, NULL); } - purple_account_add_buddy(account, buddy); + purple_account_add_buddy_with_invite(account, buddy, invite); } static void @@ -680,6 +681,9 @@ field = purple_request_field_string_new("alias", _("Alias (optional)"), alias, FALSE); purple_request_field_group_add_field(group, field); + field = purple_request_field_string_new("invite", _("Invite message (optional)"), NULL, FALSE); + purple_request_field_group_add_field(group, field); + field = purple_request_field_string_new("group", _("Add in group"), grp, FALSE); purple_request_field_group_add_field(group, field); purple_request_field_set_type_hint(field, "group"); diff -r a92f4cb593a4 -r 974722699032 libpurple/Makefile.am --- a/libpurple/Makefile.am Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/Makefile.am Mon Apr 25 20:13:05 2011 +0000 @@ -32,7 +32,7 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = purple.pc -SUBDIRS = $(GCONF_DIR) plugins protocols . tests example +SUBDIRS = $(GCONF_DIR) plugins protocols ciphers . tests example purple_coresources = \ account.c \ @@ -311,6 +311,7 @@ $(GSTREAMER_LIBS) \ $(GSTINTERFACES_LIBS) \ $(IDN_LIBS) \ + ciphers/libpurple-ciphers.la \ -lm AM_CPPFLAGS = \ diff -r a92f4cb593a4 -r 974722699032 libpurple/Makefile.mingw --- a/libpurple/Makefile.mingw Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/Makefile.mingw Mon Apr 25 20:13:05 2011 +0000 @@ -35,6 +35,14 @@ buddyicon.c \ certificate.c \ cipher.c \ + ciphers/des.c \ + ciphers/gchecksum.c \ + ciphers/hmac.c \ + ciphers/md4.c \ + ciphers/md5.c \ + ciphers/rc4.c \ + ciphers/sha1.c \ + ciphers/sha256.c \ circbuffer.c \ cmds.c \ connection.c \ diff -r a92f4cb593a4 -r 974722699032 libpurple/account.c --- a/libpurple/account.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/account.c Mon Apr 25 20:13:05 2011 +0000 @@ -1441,6 +1441,27 @@ return NULL; } + plugin_return = GPOINTER_TO_INT( + purple_signal_emit_return_1( + purple_accounts_get_handle(), + "account-authorization-requested-with-message", + account, remote_user, message + )); + + switch (plugin_return) + { + case PURPLE_ACCOUNT_RESPONSE_IGNORE: + return NULL; + case PURPLE_ACCOUNT_RESPONSE_ACCEPT: + if (auth_cb != NULL) + auth_cb(user_data); + return NULL; + case PURPLE_ACCOUNT_RESPONSE_DENY: + if (deny_cb != NULL) + deny_cb(user_data); + return NULL; + } + if (ui_ops != NULL && ui_ops->request_authorize != NULL) { info = g_new0(PurpleAccountRequestInfo, 1); info->type = PURPLE_ACCOUNT_REQUEST_AUTHORIZATION; @@ -1915,6 +1936,20 @@ } } +gboolean +purple_account_get_silence_suppression(const PurpleAccount *account) +{ + return purple_account_get_bool(account, "silence-suppression", FALSE); +} + +void +purple_account_set_silence_suppression(PurpleAccount *account, gboolean value) +{ + g_return_if_fail(account != NULL); + + purple_account_set_bool(account, "silence-suppression", value); +} + void purple_account_clear_settings(PurpleAccount *account) { @@ -2505,8 +2540,37 @@ if (prpl != NULL) prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); - if (prpl_info != NULL && prpl_info->add_buddy != NULL) - prpl_info->add_buddy(gc, buddy, purple_buddy_get_group(buddy)); + if (prpl_info != NULL) { + if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite)) + prpl_info->add_buddy_with_invite(gc, buddy, purple_buddy_get_group(buddy), NULL); + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy)) + prpl_info->add_buddy(gc, buddy, purple_buddy_get_group(buddy)); + } +} + +void +purple_account_add_buddy_with_invite(PurpleAccount *account, PurpleBuddy *buddy, const char *message) +{ + PurplePluginProtocolInfo *prpl_info = NULL; + PurpleConnection *gc; + PurplePlugin *prpl = NULL; + + g_return_if_fail(account != NULL); + g_return_if_fail(buddy != NULL); + + gc = purple_account_get_connection(account); + if (gc != NULL) + prpl = purple_connection_get_prpl(gc); + + if (prpl != NULL) + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + + if (prpl_info != NULL) { + if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite)) + prpl_info->add_buddy_with_invite(gc, buddy, purple_buddy_get_group(buddy), message); + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy)) + prpl_info->add_buddy(gc, buddy, purple_buddy_get_group(buddy)); + } } void @@ -2531,9 +2595,69 @@ groups = g_list_append(groups, purple_buddy_get_group(buddy)); } - if (prpl_info->add_buddies != NULL) + if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies_with_invite)) + prpl_info->add_buddies_with_invite(gc, buddies, groups, NULL); + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies)) prpl_info->add_buddies(gc, buddies, groups); - else if (prpl_info->add_buddy != NULL) { + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite)) { + GList *curb = buddies, *curg = groups; + + while ((curb != NULL) && (curg != NULL)) { + prpl_info->add_buddy_with_invite(gc, curb->data, curg->data, NULL); + curb = curb->next; + curg = curg->next; + } + } + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy)) { + GList *curb = buddies, *curg = groups; + + while ((curb != NULL) && (curg != NULL)) { + prpl_info->add_buddy(gc, curb->data, curg->data); + curb = curb->next; + curg = curg->next; + } + } + + g_list_free(groups); + } +} + +void +purple_account_add_buddies_with_invite(PurpleAccount *account, GList *buddies, const char *message) +{ + PurplePluginProtocolInfo *prpl_info = NULL; + PurpleConnection *gc = purple_account_get_connection(account); + PurplePlugin *prpl = NULL; + + if (gc != NULL) + prpl = purple_connection_get_prpl(gc); + + if (prpl != NULL) + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + + if (prpl_info) { + GList *cur, *groups = NULL; + + /* Make a list of what group each buddy is in */ + for (cur = buddies; cur != NULL; cur = cur->next) { + PurpleBuddy *buddy = cur->data; + groups = g_list_append(groups, purple_buddy_get_group(buddy)); + } + + if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies_with_invite)) + prpl_info->add_buddies_with_invite(gc, buddies, groups, message); + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite)) { + GList *curb = buddies, *curg = groups; + + while ((curb != NULL) && (curg != NULL)) { + prpl_info->add_buddy_with_invite(gc, curb->data, curg->data, message); + curb = curb->next; + curg = curg->next; + } + } + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies)) + prpl_info->add_buddies(gc, buddies, groups); + else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy)) { GList *curb = buddies, *curg = groups; while ((curb != NULL) && (curg != NULL)) { @@ -3046,6 +3170,13 @@ PURPLE_SUBTYPE_ACCOUNT), purple_value_new(PURPLE_TYPE_STRING)); + purple_signal_register(handle, "account-authorization-requested-with-message", + purple_marshal_INT__POINTER_POINTER_POINTER, + purple_value_new(PURPLE_TYPE_INT), 3, + purple_value_new(PURPLE_TYPE_SUBTYPE, + PURPLE_SUBTYPE_ACCOUNT), + purple_value_new(PURPLE_TYPE_STRING), + purple_value_new(PURPLE_TYPE_STRING)); purple_signal_register(handle, "account-authorization-denied", purple_marshal_VOID__POINTER_POINTER, NULL, 2, purple_value_new(PURPLE_TYPE_SUBTYPE, diff -r a92f4cb593a4 -r 974722699032 libpurple/account.h --- a/libpurple/account.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/account.h Mon Apr 25 20:13:05 2011 +0000 @@ -59,6 +59,16 @@ PURPLE_ACCOUNT_REQUEST_AUTHORIZATION = 0 /* Account authorization request */ } PurpleAccountRequestType; +/** + * Account request response types + */ +typedef enum +{ + PURPLE_ACCOUNT_RESPONSE_IGNORE = -2, + PURPLE_ACCOUNT_RESPONSE_DENY = -1, + PURPLE_ACCOUNT_RESPONSE_PASS = 0, + PURPLE_ACCOUNT_RESPONSE_ACCEPT = 1 +} PurpleAccountRequestResponse; /** Account UI operations, used to notify the user of status changes and when * buddies add this account to their buddy lists. @@ -143,6 +153,7 @@ * buddies are added to your permit list. Currently we have to * iterate through the entire list if we want to check if someone * is permitted or denied. We should do this for 3.0.0. + * Or maybe use a GTree. */ GSList *permit; /**< Permit list. */ GSList *deny; /**< Deny list. */ @@ -502,6 +513,24 @@ PurpleGetPublicAliasFailureCallback failure_cb); /** + * Return whether silence suppression is used during voice call. + * + * @param account The account. + * + * @return @c TRUE if suppression is used, or @c FALSE if not. + */ +gboolean purple_account_get_silence_suppression(const PurpleAccount *account); + +/** + * Sets whether silence suppression is used during voice call. + * + * @param account The account. + * @param value @c TRUE if suppression should be used. + */ +void purple_account_set_silence_suppression(PurpleAccount *account, + gboolean value); + +/** * Clears all protocol-specific settings on an account. * * @param account The account. @@ -929,15 +958,40 @@ * * @param account The account. * @param buddy The buddy to add. + * + * @deprecated Use purple_account_add_buddy_with_invite and \c NULL message. */ void purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy); /** + * Adds a buddy to the server-side buddy list for the specified account. + * + * @param account The account. + * @param buddy The buddy to add. + * @param message The invite message. This may be ignored by a prpl. + * + * @since 2.8.0 + */ +void purple_account_add_buddy_with_invite(PurpleAccount *account, PurpleBuddy *buddy, const char *message); + +/** * Adds a list of buddies to the server-side buddy list. * * @param account The account. * @param buddies The list of PurpleBlistNodes representing the buddies to add. + * + * @deprecated Use purple_account_add_buddies_with_invite and \c NULL message. */ void purple_account_add_buddies(PurpleAccount *account, GList *buddies); +/** + * Adds a list of buddies to the server-side buddy list. + * + * @param account The account. + * @param buddies The list of PurpleBlistNodes representing the buddies to add. + * @param message The invite message. This may be ignored by a prpl. + * + * @since 2.8.0 + */ +void purple_account_add_buddies_with_invite(PurpleAccount *account, GList *buddies, const char *message); /** * Removes a buddy from the server-side buddy list. diff -r a92f4cb593a4 -r 974722699032 libpurple/cipher.c --- a/libpurple/cipher.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/cipher.c Mon Apr 25 20:13:05 2011 +0000 @@ -5,23 +5,6 @@ * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * - * Original md5 - * Copyright (C) 2001-2003 Christophe Devine - * - * Original md4 taken from linux kernel - * MD4 Message Digest Algorithm (RFC1320). - * - * Implementation derived from Andrew Tridgell and Steve French's - * CIFS MD4 implementation, and the cryptoapi implementation - * originally based on the public domain implementation written - * by Colin Plumb in 1993. - * - * Copyright (c) Andrew Tridgell 1997-1998. - * Modified by Steve French (sfrench@us.ibm.com) 2002 - * Copyright (c) Cryptoapi developers. - * Copyright (c) 2002 David S. Miller (davem@redhat.com) - * Copyright (c) 2002 James Morris - * * Original des taken from gpg * * des.c - DES and Triple-DES encryption/decryption Algorithm @@ -57,2454 +40,6 @@ #include "signals.h" #include "value.h" -#if GLIB_CHECK_VERSION(2,16,0) -static void -purple_g_checksum_init(PurpleCipherContext *context, GChecksumType type) -{ - GChecksum *checksum; - - checksum = g_checksum_new(type); - purple_cipher_context_set_data(context, checksum); -} - -static void -purple_g_checksum_reset(PurpleCipherContext *context, GChecksumType type) -{ - GChecksum *checksum; - - checksum = purple_cipher_context_get_data(context); - g_return_if_fail(checksum != NULL); - -#if GLIB_CHECK_VERSION(2,18,0) - g_checksum_reset(checksum); -#else - g_checksum_free(checksum); - checksum = g_checksum_new(type); - purple_cipher_context_set_data(context, checksum); -#endif -} - -static void -purple_g_checksum_uninit(PurpleCipherContext *context) -{ - GChecksum *checksum; - - checksum = purple_cipher_context_get_data(context); - g_return_if_fail(checksum != NULL); - - g_checksum_free(checksum); -} - -static void -purple_g_checksum_append(PurpleCipherContext *context, const guchar *data, - gsize len) -{ - GChecksum *checksum; - - checksum = purple_cipher_context_get_data(context); - g_return_if_fail(checksum != NULL); - - while (len >= G_MAXSSIZE) { - g_checksum_update(checksum, data, G_MAXSSIZE); - len -= G_MAXSSIZE; - data += G_MAXSSIZE; - } - - if (len) - g_checksum_update(checksum, data, len); -} - -static gboolean -purple_g_checksum_digest(PurpleCipherContext *context, GChecksumType type, - gsize len, guchar *digest, gsize *out_len) -{ - GChecksum *checksum; - const gssize required_length = g_checksum_type_get_length(type); - - checksum = purple_cipher_context_get_data(context); - - g_return_val_if_fail(len >= required_length, FALSE); - g_return_val_if_fail(checksum != NULL, FALSE); - - g_checksum_get_digest(checksum, digest, &len); - - purple_cipher_context_reset(context, NULL); - - if (out_len) - *out_len = len; - - return TRUE; -} -#endif - - -/******************************************************************************* - * MD5 - ******************************************************************************/ -#define MD5_HMAC_BLOCK_SIZE 64 - -static size_t -md5_get_block_size(PurpleCipherContext *context) -{ - /* This does not change (in this case) */ - return MD5_HMAC_BLOCK_SIZE; -} - -#if GLIB_CHECK_VERSION(2,16,0) - -static void -md5_init(PurpleCipherContext *context, void *extra) -{ - purple_g_checksum_init(context, G_CHECKSUM_MD5); -} - -static void -md5_reset(PurpleCipherContext *context, void *extra) -{ - purple_g_checksum_reset(context, G_CHECKSUM_MD5); -} - -static gboolean -md5_digest(PurpleCipherContext *context, gsize in_len, guchar digest[16], - size_t *out_len) -{ - return purple_g_checksum_digest(context, G_CHECKSUM_MD5, in_len, - digest, out_len); -} - -static PurpleCipherOps MD5Ops = { - NULL, /* Set Option */ - NULL, /* Get Option */ - md5_init, /* init */ - md5_reset, /* reset */ - purple_g_checksum_uninit, /* uninit */ - NULL, /* set iv */ - purple_g_checksum_append, /* append */ - md5_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - NULL, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - md5_get_block_size, /* get block size */ - NULL /* set key with len */ -}; - -#else /* GLIB_CHECK_VERSION(2,16,0) */ - -struct MD5Context { - guint32 total[2]; - guint32 state[4]; - guchar buffer[64]; -}; - -#define MD5_GET_GUINT32(n,b,i) { \ - (n) = ((guint32)(b) [(i) ] ) \ - | ((guint32)(b) [(i) + 1] << 8) \ - | ((guint32)(b) [(i) + 2] << 16) \ - | ((guint32)(b) [(i) + 3] << 24); \ -} -#define MD5_PUT_GUINT32(n,b,i) { \ - (b)[(i) ] = (guchar)((n) ); \ - (b)[(i) + 1] = (guchar)((n) >> 8); \ - (b)[(i) + 2] = (guchar)((n) >> 16); \ - (b)[(i) + 3] = (guchar)((n) >> 24); \ -} - -static void -md5_init(PurpleCipherContext *context, gpointer extra) { - struct MD5Context *md5_context; - - md5_context = g_new0(struct MD5Context, 1); - - purple_cipher_context_set_data(context, md5_context); - - purple_cipher_context_reset(context, extra); -} - -static void -md5_reset(PurpleCipherContext *context, gpointer extra) { - struct MD5Context *md5_context; - - md5_context = purple_cipher_context_get_data(context); - - md5_context->total[0] = 0; - md5_context->total[1] = 0; - - md5_context->state[0] = 0x67452301; - md5_context->state[1] = 0xEFCDAB89; - md5_context->state[2] = 0x98BADCFE; - md5_context->state[3] = 0x10325476; - - memset(md5_context->buffer, 0, sizeof(md5_context->buffer)); -} - -static void -md5_uninit(PurpleCipherContext *context) { - struct MD5Context *md5_context; - - purple_cipher_context_reset(context, NULL); - - md5_context = purple_cipher_context_get_data(context); - memset(md5_context, 0, sizeof(md5_context)); - - g_free(md5_context); - md5_context = NULL; -} - -static void -md5_process(struct MD5Context *md5_context, const guchar data[64]) { - guint32 X[16], A, B, C, D; - - A = md5_context->state[0]; - B = md5_context->state[1]; - C = md5_context->state[2]; - D = md5_context->state[3]; - - MD5_GET_GUINT32(X[ 0], data, 0); - MD5_GET_GUINT32(X[ 1], data, 4); - MD5_GET_GUINT32(X[ 2], data, 8); - MD5_GET_GUINT32(X[ 3], data, 12); - MD5_GET_GUINT32(X[ 4], data, 16); - MD5_GET_GUINT32(X[ 5], data, 20); - MD5_GET_GUINT32(X[ 6], data, 24); - MD5_GET_GUINT32(X[ 7], data, 28); - MD5_GET_GUINT32(X[ 8], data, 32); - MD5_GET_GUINT32(X[ 9], data, 36); - MD5_GET_GUINT32(X[10], data, 40); - MD5_GET_GUINT32(X[11], data, 44); - MD5_GET_GUINT32(X[12], data, 48); - MD5_GET_GUINT32(X[13], data, 52); - MD5_GET_GUINT32(X[14], data, 56); - MD5_GET_GUINT32(X[15], data, 60); - - #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) - #define P(a,b,c,d,k,s,t) { \ - a += F(b,c,d) + X[k] + t; \ - a = S(a,s) + b; \ - } - - /* first pass */ - #define F(x,y,z) (z ^ (x & (y ^ z))) - P(A, B, C, D, 0, 7, 0xD76AA478); - P(D, A, B, C, 1, 12, 0xE8C7B756); - P(C, D, A, B, 2, 17, 0x242070DB); - P(B, C, D, A, 3, 22, 0xC1BDCEEE); - P(A, B, C, D, 4, 7, 0xF57C0FAF); - P(D, A, B, C, 5, 12, 0x4787C62A); - P(C, D, A, B, 6, 17, 0xA8304613); - P(B, C, D, A, 7, 22, 0xFD469501); - P(A, B, C, D, 8, 7, 0x698098D8); - P(D, A, B, C, 9, 12, 0x8B44F7AF); - P(C, D, A, B, 10, 17, 0xFFFF5BB1); - P(B, C, D, A, 11, 22, 0x895CD7BE); - P(A, B, C, D, 12, 7, 0x6B901122); - P(D, A, B, C, 13, 12, 0xFD987193); - P(C, D, A, B, 14, 17, 0xA679438E); - P(B, C, D, A, 15, 22, 0x49B40821); - #undef F - - /* second pass */ - #define F(x,y,z) (y ^ (z & (x ^ y))) - P(A, B, C, D, 1, 5, 0xF61E2562); - P(D, A, B, C, 6, 9, 0xC040B340); - P(C, D, A, B, 11, 14, 0x265E5A51); - P(B, C, D, A, 0, 20, 0xE9B6C7AA); - P(A, B, C, D, 5, 5, 0xD62F105D); - P(D, A, B, C, 10, 9, 0x02441453); - P(C, D, A, B, 15, 14, 0xD8A1E681); - P(B, C, D, A, 4, 20, 0xE7D3FBC8); - P(A, B, C, D, 9, 5, 0x21E1CDE6); - P(D, A, B, C, 14, 9, 0xC33707D6); - P(C, D, A, B, 3, 14, 0xF4D50D87); - P(B, C, D, A, 8, 20, 0x455A14ED); - P(A, B, C, D, 13, 5, 0xA9E3E905); - P(D, A, B, C, 2, 9, 0xFCEFA3F8); - P(C, D, A, B, 7, 14, 0x676F02D9); - P(B, C, D, A, 12, 20, 0x8D2A4C8A); - #undef F - - /* third pass */ - #define F(x,y,z) (x ^ y ^ z) - P(A, B, C, D, 5, 4, 0xFFFA3942); - P(D, A, B, C, 8, 11, 0x8771F681); - P(C, D, A, B, 11, 16, 0x6D9D6122); - P(B, C, D, A, 14, 23, 0xFDE5380C); - P(A, B, C, D, 1, 4, 0xA4BEEA44); - P(D, A, B, C, 4, 11, 0x4BDECFA9); - P(C, D, A, B, 7, 16, 0xF6BB4B60); - P(B, C, D, A, 10, 23, 0xBEBFBC70); - P(A, B, C, D, 13, 4, 0x289B7EC6); - P(D, A, B, C, 0, 11, 0xEAA127FA); - P(C, D, A, B, 3, 16, 0xD4EF3085); - P(B, C, D, A, 6, 23, 0x04881D05); - P(A, B, C, D, 9, 4, 0xD9D4D039); - P(D, A, B, C, 12, 11, 0xE6DB99E5); - P(C, D, A, B, 15, 16, 0x1FA27CF8); - P(B, C, D, A, 2, 23, 0xC4AC5665); - #undef F - - /* forth pass */ - #define F(x,y,z) (y ^ (x | ~z)) - P(A, B, C, D, 0, 6, 0xF4292244); - P(D, A, B, C, 7, 10, 0x432AFF97); - P(C, D, A, B, 14, 15, 0xAB9423A7); - P(B, C, D, A, 5, 21, 0xFC93A039); - P(A, B, C, D, 12, 6, 0x655B59C3); - P(D, A, B, C, 3, 10, 0x8F0CCC92); - P(C, D, A, B, 10, 15, 0xFFEFF47D); - P(B, C, D, A, 1, 21, 0x85845DD1); - P(A, B, C, D, 8, 6, 0x6FA87E4F); - P(D, A, B, C, 15, 10, 0xFE2CE6E0); - P(C, D, A, B, 6, 15, 0xA3014314); - P(B, C, D, A, 13, 21, 0x4E0811A1); - P(A, B, C, D, 4, 6, 0xF7537E82); - P(D, A, B, C, 11, 10, 0xBD3AF235); - P(C, D, A, B, 2, 15, 0x2AD7D2BB); - P(B, C, D, A, 9, 21, 0xEB86D391); - #undef F - #undef P - #undef S - - md5_context->state[0] += A; - md5_context->state[1] += B; - md5_context->state[2] += C; - md5_context->state[3] += D; -} - -static void -md5_append(PurpleCipherContext *context, const guchar *data, size_t len) { - struct MD5Context *md5_context = NULL; - guint32 left = 0, fill = 0; - - g_return_if_fail(context != NULL); - - md5_context = purple_cipher_context_get_data(context); - g_return_if_fail(md5_context != NULL); - - left = md5_context->total[0] & 0x3F; - fill = 64 - left; - - md5_context->total[0] += len; - md5_context->total[0] &= 0xFFFFFFFF; - - if(md5_context->total[0] < len) - md5_context->total[1]++; - - if(left && len >= fill) { - memcpy((md5_context->buffer + left), data, fill); - md5_process(md5_context, md5_context->buffer); - len -= fill; - data += fill; - left = 0; - } - - while(len >= 64) { - md5_process(md5_context, data); - len -= 64; - data += 64; - } - - if(len) { - memcpy((md5_context->buffer + left), data, len); - } -} - -static gboolean -md5_digest(PurpleCipherContext *context, size_t in_len, guchar digest[16], - size_t *out_len) -{ - struct MD5Context *md5_context = NULL; - guint32 last, pad; - guint32 high, low; - guchar message[8]; - guchar padding[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - g_return_val_if_fail(in_len >= 16, FALSE); - - md5_context = purple_cipher_context_get_data(context); - - high = (md5_context->total[0] >> 29) - | (md5_context->total[1] << 3); - low = (md5_context->total[0] << 3); - - MD5_PUT_GUINT32(low, message, 0); - MD5_PUT_GUINT32(high, message, 4); - - last = md5_context->total[0] & 0x3F; - pad = (last < 56) ? (56 - last) : (120 - last); - - md5_append(context, padding, pad); - md5_append(context, message, 8); - - MD5_PUT_GUINT32(md5_context->state[0], digest, 0); - MD5_PUT_GUINT32(md5_context->state[1], digest, 4); - MD5_PUT_GUINT32(md5_context->state[2], digest, 8); - MD5_PUT_GUINT32(md5_context->state[3], digest, 12); - - if(out_len) - *out_len = 16; - - return TRUE; -} - -static PurpleCipherOps MD5Ops = { - NULL, /* Set option */ - NULL, /* Get option */ - md5_init, /* init */ - md5_reset, /* reset */ - md5_uninit, /* uninit */ - NULL, /* set iv */ - md5_append, /* append */ - md5_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - NULL, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - md5_get_block_size, /* get block size */ - NULL /* set key with len */ -}; - -#endif /* GLIB_CHECK_VERSION(2,16,0) */ - -/******************************************************************************* - * MD4 - ******************************************************************************/ -#define MD4_DIGEST_SIZE 16 -#define MD4_HMAC_BLOCK_SIZE 64 -#define MD4_BLOCK_WORDS 16 -#define MD4_HASH_WORDS 4 - - - -struct MD4_Context { - guint32 hash[MD4_HASH_WORDS]; - guint32 block[MD4_BLOCK_WORDS]; - guint64 byte_count; -}; - -static inline guint32 lshift(guint32 x, unsigned int s) -{ - x &= 0xFFFFFFFF; - return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); -} - -static inline guint32 F(guint32 x, guint32 y, guint32 z) -{ - return (x & y) | ((~x) & z); -} - -static inline guint32 G(guint32 x, guint32 y, guint32 z) -{ - return (x & y) | (x & z) | (y & z); -} - -static inline guint32 H(guint32 x, guint32 y, guint32 z) -{ - return x ^ y ^ z; -} - -#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s)) -#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (guint32)0x5A827999,s)) -#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (guint32)0x6ED9EBA1,s)) - -static inline void le32_to_cpu_array(guint32 *buf, unsigned int words) -{ - while (words--) { - *buf=GUINT_FROM_LE(*buf); - buf++; - } -} - -static inline void cpu_to_le32_array(guint32 *buf, unsigned int words) -{ - while (words--) { - *buf=GUINT_TO_LE(*buf); - buf++; - } -} - -static void md4_transform(guint32 *hash, guint32 const *in) -{ - guint32 a, b, c, d; - - a = hash[0]; - b = hash[1]; - c = hash[2]; - d = hash[3]; - - ROUND1(a, b, c, d, in[0], 3); - ROUND1(d, a, b, c, in[1], 7); - ROUND1(c, d, a, b, in[2], 11); - ROUND1(b, c, d, a, in[3], 19); - ROUND1(a, b, c, d, in[4], 3); - ROUND1(d, a, b, c, in[5], 7); - ROUND1(c, d, a, b, in[6], 11); - ROUND1(b, c, d, a, in[7], 19); - ROUND1(a, b, c, d, in[8], 3); - ROUND1(d, a, b, c, in[9], 7); - ROUND1(c, d, a, b, in[10], 11); - ROUND1(b, c, d, a, in[11], 19); - ROUND1(a, b, c, d, in[12], 3); - ROUND1(d, a, b, c, in[13], 7); - ROUND1(c, d, a, b, in[14], 11); - ROUND1(b, c, d, a, in[15], 19); - - ROUND2(a, b, c, d,in[ 0], 3); - ROUND2(d, a, b, c, in[4], 5); - ROUND2(c, d, a, b, in[8], 9); - ROUND2(b, c, d, a, in[12], 13); - ROUND2(a, b, c, d, in[1], 3); - ROUND2(d, a, b, c, in[5], 5); - ROUND2(c, d, a, b, in[9], 9); - ROUND2(b, c, d, a, in[13], 13); - ROUND2(a, b, c, d, in[2], 3); - ROUND2(d, a, b, c, in[6], 5); - ROUND2(c, d, a, b, in[10], 9); - ROUND2(b, c, d, a, in[14], 13); - ROUND2(a, b, c, d, in[3], 3); - ROUND2(d, a, b, c, in[7], 5); - ROUND2(c, d, a, b, in[11], 9); - ROUND2(b, c, d, a, in[15], 13); - - ROUND3(a, b, c, d,in[ 0], 3); - ROUND3(d, a, b, c, in[8], 9); - ROUND3(c, d, a, b, in[4], 11); - ROUND3(b, c, d, a, in[12], 15); - ROUND3(a, b, c, d, in[2], 3); - ROUND3(d, a, b, c, in[10], 9); - ROUND3(c, d, a, b, in[6], 11); - ROUND3(b, c, d, a, in[14], 15); - ROUND3(a, b, c, d, in[1], 3); - ROUND3(d, a, b, c, in[9], 9); - ROUND3(c, d, a, b, in[5], 11); - ROUND3(b, c, d, a, in[13], 15); - ROUND3(a, b, c, d, in[3], 3); - ROUND3(d, a, b, c, in[11], 9); - ROUND3(c, d, a, b, in[7], 11); - ROUND3(b, c, d, a, in[15], 15); - - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; -} - -static inline void md4_transform_helper(struct MD4_Context *ctx) -{ - le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(guint32)); - md4_transform(ctx->hash, ctx->block); -} - -static void -md4_init(PurpleCipherContext *context, gpointer extra) { - struct MD4_Context *mctx; - mctx = g_new0(struct MD4_Context, 1); - purple_cipher_context_set_data(context, mctx); - purple_cipher_context_reset(context, extra); - - mctx->hash[0] = 0x67452301; - mctx->hash[1] = 0xefcdab89; - mctx->hash[2] = 0x98badcfe; - mctx->hash[3] = 0x10325476; - mctx->byte_count = 0; -} - -static void -md4_reset(PurpleCipherContext *context, gpointer extra) { - struct MD4_Context *mctx; - - mctx = purple_cipher_context_get_data(context); - - mctx->hash[0] = 0x67452301; - mctx->hash[1] = 0xefcdab89; - mctx->hash[2] = 0x98badcfe; - mctx->hash[3] = 0x10325476; - mctx->byte_count = 0; -} - -static void -md4_append(PurpleCipherContext *context, const guchar *data, size_t len) -{ - struct MD4_Context *mctx = purple_cipher_context_get_data(context); - const guint32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); - - mctx->byte_count += len; - - if (avail > len) { - memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), - data, len); - return; - } - - memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), - data, avail); - - md4_transform_helper(mctx); - data += avail; - len -= avail; - - while (len >= sizeof(mctx->block)) { - memcpy(mctx->block, data, sizeof(mctx->block)); - md4_transform_helper(mctx); - data += sizeof(mctx->block); - len -= sizeof(mctx->block); - } - - memcpy(mctx->block, data, len); -} - -static gboolean -md4_digest(PurpleCipherContext *context, size_t in_len, guchar *out, - size_t *out_len) -{ - struct MD4_Context *mctx = purple_cipher_context_get_data(context); - const unsigned int offset = mctx->byte_count & 0x3f; - char *p = (char *)mctx->block + offset; - int padding = 56 - (offset + 1); - - - if(in_len<16) return FALSE; - if(out_len) *out_len = 16; - *p++ = 0x80; - if (padding < 0) { - memset(p, 0x00, padding + sizeof (guint64)); - md4_transform_helper(mctx); - p = (char *)mctx->block; - padding = 56; - } - - memset(p, 0, padding); - mctx->block[14] = mctx->byte_count << 3; - mctx->block[15] = mctx->byte_count >> 29; - le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - - sizeof(guint64)) / sizeof(guint32)); - md4_transform(mctx->hash, mctx->block); - cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(guint32)); - memcpy(out, mctx->hash, sizeof(mctx->hash)); - memset(mctx, 0, sizeof(*mctx)); - return TRUE; -} - -static void -md4_uninit(PurpleCipherContext *context) { - struct MD4_Context *md4_context; - - purple_cipher_context_reset(context, NULL); - - md4_context = purple_cipher_context_get_data(context); - memset(md4_context, 0, sizeof(md4_context)); - - g_free(md4_context); - md4_context = NULL; -} - -static size_t -md4_get_block_size(PurpleCipherContext *context) -{ - /* This does not change (in this case) */ - return MD4_HMAC_BLOCK_SIZE; -} - -static PurpleCipherOps MD4Ops = { - NULL, /* Set option */ - NULL, /* Get option */ - md4_init, /* init */ - md4_reset, /* reset */ - md4_uninit, /* uninit */ - NULL, /* set iv */ - md4_append, /* append */ - md4_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - NULL, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - md4_get_block_size, /* get block size */ - NULL /* set key with len */ -}; - -/******************************************************************************* - * HMAC - ******************************************************************************/ - -struct HMAC_Context { - PurpleCipherContext *hash; - char *name; - int blocksize; - guchar *opad; -}; - -static void -hmac_init(PurpleCipherContext *context, gpointer extra) -{ - struct HMAC_Context *hctx; - hctx = g_new0(struct HMAC_Context, 1); - purple_cipher_context_set_data(context, hctx); - purple_cipher_context_reset(context, extra); -} - -static void -hmac_reset(PurpleCipherContext *context, gpointer extra) -{ - struct HMAC_Context *hctx; - - hctx = purple_cipher_context_get_data(context); - - g_free(hctx->name); - hctx->name = NULL; - if (hctx->hash) - purple_cipher_context_destroy(hctx->hash); - hctx->hash = NULL; - hctx->blocksize = 0; - g_free(hctx->opad); - hctx->opad = NULL; -} - -static void -hmac_set_opt(PurpleCipherContext *context, const gchar *name, void *value) -{ - struct HMAC_Context *hctx; - - hctx = purple_cipher_context_get_data(context); - - if (purple_strequal(name, "hash")) { - g_free(hctx->name); - if (hctx->hash) - purple_cipher_context_destroy(hctx->hash); - hctx->name = g_strdup((char*)value); - hctx->hash = purple_cipher_context_new_by_name((char *)value, NULL); - hctx->blocksize = purple_cipher_context_get_block_size(hctx->hash); - } -} - -static void * -hmac_get_opt(PurpleCipherContext *context, const gchar *name) -{ - struct HMAC_Context *hctx; - - hctx = purple_cipher_context_get_data(context); - - if (purple_strequal(name, "hash")) { - return hctx->name; - } - - return NULL; -} - -static void -hmac_append(PurpleCipherContext *context, const guchar *data, size_t len) -{ - struct HMAC_Context *hctx = purple_cipher_context_get_data(context); - - g_return_if_fail(hctx->hash != NULL); - - purple_cipher_context_append(hctx->hash, data, len); -} - -static gboolean -hmac_digest(PurpleCipherContext *context, size_t in_len, guchar *out, size_t *out_len) -{ - struct HMAC_Context *hctx = purple_cipher_context_get_data(context); - PurpleCipherContext *hash = hctx->hash; - guchar *inner_hash; - size_t hash_len; - gboolean result; - - g_return_val_if_fail(hash != NULL, FALSE); - - inner_hash = g_malloc(100); /* TODO: Should be enough for now... */ - result = purple_cipher_context_digest(hash, 100, inner_hash, &hash_len); - - purple_cipher_context_reset(hash, NULL); - - purple_cipher_context_append(hash, hctx->opad, hctx->blocksize); - purple_cipher_context_append(hash, inner_hash, hash_len); - - g_free(inner_hash); - - result = result && purple_cipher_context_digest(hash, in_len, out, out_len); - - return result; -} - -static void -hmac_uninit(PurpleCipherContext *context) -{ - struct HMAC_Context *hctx; - - purple_cipher_context_reset(context, NULL); - - hctx = purple_cipher_context_get_data(context); - - g_free(hctx); -} - -static void -hmac_set_key_with_len(PurpleCipherContext *context, const guchar * key, size_t key_len) -{ - struct HMAC_Context *hctx = purple_cipher_context_get_data(context); - int blocksize, i; - guchar *ipad; - guchar *full_key; - - g_return_if_fail(hctx->hash != NULL); - - g_free(hctx->opad); - - blocksize = hctx->blocksize; - ipad = g_malloc(blocksize); - hctx->opad = g_malloc(blocksize); - - if (key_len > blocksize) { - purple_cipher_context_reset(hctx->hash, NULL); - purple_cipher_context_append(hctx->hash, key, key_len); - full_key = g_malloc(100); /* TODO: Should be enough for now... */ - purple_cipher_context_digest(hctx->hash, 100, full_key, &key_len); - } else - full_key = g_memdup(key, key_len); - - if (key_len < blocksize) { - full_key = g_realloc(full_key, blocksize); - memset(full_key + key_len, 0, blocksize - key_len); - } - - for(i = 0; i < blocksize; i++) { - ipad[i] = 0x36 ^ full_key[i]; - hctx->opad[i] = 0x5c ^ full_key[i]; - } - - g_free(full_key); - - purple_cipher_context_reset(hctx->hash, NULL); - purple_cipher_context_append(hctx->hash, ipad, blocksize); - g_free(ipad); -} - -static void -hmac_set_key(PurpleCipherContext *context, const guchar * key) -{ - hmac_set_key_with_len(context, key, strlen((char *)key)); -} - -static size_t -hmac_get_block_size(PurpleCipherContext *context) -{ - struct HMAC_Context *hctx = purple_cipher_context_get_data(context); - - return hctx->blocksize; -} - -static PurpleCipherOps HMACOps = { - hmac_set_opt, /* Set option */ - hmac_get_opt, /* Get option */ - hmac_init, /* init */ - hmac_reset, /* reset */ - hmac_uninit, /* uninit */ - NULL, /* set iv */ - hmac_append, /* append */ - hmac_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - hmac_set_key, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - hmac_get_block_size, /* get block size */ - hmac_set_key_with_len /* set key with len */ -}; - -/****************************************************************************** - * DES - *****************************************************************************/ - -typedef struct _des_ctx -{ - guint32 encrypt_subkeys[32]; - guint32 decrypt_subkeys[32]; -} des_ctx[1]; - -/* - * The s-box values are permuted according to the 'primitive function P' - */ -static const guint32 sbox1[64] = -{ - 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000, - 0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002, - 0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202, - 0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000, - 0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200, - 0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202, - 0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200, - 0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002 -}; - -static const guint32 sbox2[64] = -{ - 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010, - 0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010, - 0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000, - 0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010, - 0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000, - 0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000, - 0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010, - 0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000 -}; - -static const guint32 sbox3[64] = -{ - 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100, - 0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104, - 0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104, - 0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000, - 0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000, - 0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004, - 0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004, - 0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100 -}; - -static const guint32 sbox4[64] = -{ - 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000, - 0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000, - 0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040, - 0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040, - 0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000, - 0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040, - 0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040, - 0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040 -}; - -static const guint32 sbox5[64] = -{ - 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000, - 0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000, - 0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080, - 0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080, - 0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080, - 0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000, - 0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000, - 0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080 -}; - -static const guint32 sbox6[64] = -{ - 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000, - 0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008, - 0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008, - 0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000, - 0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008, - 0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000, - 0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008, - 0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008 -}; - -static const guint32 sbox7[64] = -{ - 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400, - 0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401, - 0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001, - 0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400, - 0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001, - 0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400, - 0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401, - 0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001 -}; - -static const guint32 sbox8[64] = -{ - 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000, - 0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020, - 0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800, - 0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000, - 0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820, - 0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820, - 0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000, - 0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800 -}; - - - -/* - * * These two tables are part of the 'permuted choice 1' function. - * * In this implementation several speed improvements are done. - * */ -static const guint32 leftkey_swap[16] = -{ - 0x00000000, 0x00000001, 0x00000100, 0x00000101, - 0x00010000, 0x00010001, 0x00010100, 0x00010101, - 0x01000000, 0x01000001, 0x01000100, 0x01000101, - 0x01010000, 0x01010001, 0x01010100, 0x01010101 -}; - -static const guint32 rightkey_swap[16] = -{ - 0x00000000, 0x01000000, 0x00010000, 0x01010000, - 0x00000100, 0x01000100, 0x00010100, 0x01010100, - 0x00000001, 0x01000001, 0x00010001, 0x01010001, - 0x00000101, 0x01000101, 0x00010101, 0x01010101, -}; - - - -/* - * Numbers of left shifts per round for encryption subkey schedule - * To calculate the decryption key scheduling we just reverse the - * ordering of the subkeys so we can omit the table for decryption - * subkey schedule. - */ -static const guint8 encrypt_rotate_tab[16] = -{ - 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 -}; - -/* - * Macro to swap bits across two words - **/ -#define DO_PERMUTATION(a, temp, b, offset, mask) \ - temp = ((a>>offset) ^ b) & mask; \ -b ^= temp; \ -a ^= temp<>31)) ^ *subkey++; \ -to ^= sbox8[ work & 0x3f ]; \ -to ^= sbox6[ (work>>8) & 0x3f ]; \ -to ^= sbox4[ (work>>16) & 0x3f ]; \ -to ^= sbox2[ (work>>24) & 0x3f ]; \ -work = ((from>>3) | (from<<29)) ^ *subkey++; \ -to ^= sbox7[ work & 0x3f ]; \ -to ^= sbox5[ (work>>8) & 0x3f ]; \ -to ^= sbox3[ (work>>16) & 0x3f ]; \ -to ^= sbox1[ (work>>24) & 0x3f ]; - - -/* - * Macros to convert 8 bytes from/to 32bit words - **/ -#define READ_64BIT_DATA(data, left, right) \ - left = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \ -right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7]; - -#define WRITE_64BIT_DATA(data, left, right) \ - data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff; \ -data[2] = (left >> 8) &0xff; data[3] = left &0xff; \ -data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff; \ -data[6] = (right >> 8) &0xff; data[7] = right &0xff; - - - - - - -/* - * des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for - * 16 encryption rounds. - * To calculate subkeys for decryption the caller - * have to reorder the generated subkeys. - * - * rawkey: 8 Bytes of key data - * subkey: Array of at least 32 guint32s. Will be filled - * with calculated subkeys. - * - **/ -static void -des_key_schedule (const guint8 * rawkey, guint32 * subkey) -{ - guint32 left, right, work; - int round; - - READ_64BIT_DATA (rawkey, left, right) - - DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f) - DO_PERMUTATION (right, work, left, 0, 0x10101010) - - left = (leftkey_swap[(left >> 0) & 0xf] << 3) | (leftkey_swap[(left >> 8) & 0xf] << 2) - | (leftkey_swap[(left >> 16) & 0xf] << 1) | (leftkey_swap[(left >> 24) & 0xf]) - | (leftkey_swap[(left >> 5) & 0xf] << 7) | (leftkey_swap[(left >> 13) & 0xf] << 6) - | (leftkey_swap[(left >> 21) & 0xf] << 5) | (leftkey_swap[(left >> 29) & 0xf] << 4); - - left &= 0x0fffffff; - - right = (rightkey_swap[(right >> 1) & 0xf] << 3) | (rightkey_swap[(right >> 9) & 0xf] << 2) - | (rightkey_swap[(right >> 17) & 0xf] << 1) | (rightkey_swap[(right >> 25) & 0xf]) - | (rightkey_swap[(right >> 4) & 0xf] << 7) | (rightkey_swap[(right >> 12) & 0xf] << 6) - | (rightkey_swap[(right >> 20) & 0xf] << 5) | (rightkey_swap[(right >> 28) & 0xf] << 4); - - right &= 0x0fffffff; - - for (round = 0; round < 16; ++round) - { - left = ((left << encrypt_rotate_tab[round]) | (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff; - right = ((right << encrypt_rotate_tab[round]) | (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff; - - *subkey++ = ((left << 4) & 0x24000000) - | ((left << 28) & 0x10000000) - | ((left << 14) & 0x08000000) - | ((left << 18) & 0x02080000) - | ((left << 6) & 0x01000000) - | ((left << 9) & 0x00200000) - | ((left >> 1) & 0x00100000) - | ((left << 10) & 0x00040000) - | ((left << 2) & 0x00020000) - | ((left >> 10) & 0x00010000) - | ((right >> 13) & 0x00002000) - | ((right >> 4) & 0x00001000) - | ((right << 6) & 0x00000800) - | ((right >> 1) & 0x00000400) - | ((right >> 14) & 0x00000200) - | (right & 0x00000100) - | ((right >> 5) & 0x00000020) - | ((right >> 10) & 0x00000010) - | ((right >> 3) & 0x00000008) - | ((right >> 18) & 0x00000004) - | ((right >> 26) & 0x00000002) - | ((right >> 24) & 0x00000001); - - *subkey++ = ((left << 15) & 0x20000000) - | ((left << 17) & 0x10000000) - | ((left << 10) & 0x08000000) - | ((left << 22) & 0x04000000) - | ((left >> 2) & 0x02000000) - | ((left << 1) & 0x01000000) - | ((left << 16) & 0x00200000) - | ((left << 11) & 0x00100000) - | ((left << 3) & 0x00080000) - | ((left >> 6) & 0x00040000) - | ((left << 15) & 0x00020000) - | ((left >> 4) & 0x00010000) - | ((right >> 2) & 0x00002000) - | ((right << 8) & 0x00001000) - | ((right >> 14) & 0x00000808) - | ((right >> 9) & 0x00000400) - | ((right) & 0x00000200) - | ((right << 7) & 0x00000100) - | ((right >> 7) & 0x00000020) - | ((right >> 3) & 0x00000011) - | ((right << 2) & 0x00000004) - | ((right >> 21) & 0x00000002); - } -} - - - -/* - * Fill a DES context with subkeys calculated from a 64bit key. - * Does not check parity bits, but simply ignore them. - * Does not check for weak keys. - **/ -static void -des_set_key (PurpleCipherContext *context, const guchar * key) -{ - struct _des_ctx *ctx = purple_cipher_context_get_data(context); - int i; - - des_key_schedule (key, ctx->encrypt_subkeys); - - for(i=0; i<32; i+=2) - { - ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i]; - ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i]; - } -} - - - -/* - * Electronic Codebook Mode DES encryption/decryption of data according - * to 'mode'. - **/ -static int -des_ecb_crypt (struct _des_ctx *ctx, const guint8 * from, guint8 * to, int mode) -{ - guint32 left, right, work; - guint32 *keys; - - keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys; - - READ_64BIT_DATA (from, left, right) - INITIAL_PERMUTATION (left, work, right) - - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) - - FINAL_PERMUTATION (right, work, left) - WRITE_64BIT_DATA (to, right, left) - - return 0; -} - -static gint -des_encrypt(PurpleCipherContext *context, const guchar data[], - size_t len, guchar output[], size_t *outlen) { - int offset = 0; - int i = 0; - int tmp; - guint8 buf[8] = {0,0,0,0,0,0,0,0}; - while(offset+8<=len) { - des_ecb_crypt(purple_cipher_context_get_data(context), - data+offset, - output+offset, - 0); - offset+=8; - } - *outlen = len; - if(offsetkey1.encrypt_subkeys); - des_key_schedule (key + 8, ctx->key2.encrypt_subkeys); - des_key_schedule (key + 16, ctx->key3.encrypt_subkeys); - - for (i = 0; i < 32; i += 2) - { - ctx->key1.decrypt_subkeys[i] = ctx->key1.encrypt_subkeys[30-i]; - ctx->key1.decrypt_subkeys[i+1] = ctx->key1.encrypt_subkeys[31-i]; - ctx->key2.decrypt_subkeys[i] = ctx->key2.encrypt_subkeys[30-i]; - ctx->key2.decrypt_subkeys[i+1] = ctx->key2.encrypt_subkeys[31-i]; - ctx->key3.decrypt_subkeys[i] = ctx->key3.encrypt_subkeys[30-i]; - ctx->key3.decrypt_subkeys[i+1] = ctx->key3.encrypt_subkeys[31-i]; - } -} - -static gint -des3_ecb_encrypt(struct _des3_ctx *ctx, const guchar data[], - size_t len, guchar output[], size_t *outlen) -{ - int offset = 0; - int i = 0; - int tmp; - guint8 buf[8] = {0,0,0,0,0,0,0,0}; - while (offset + 8 <= len) { - des_ecb_crypt(&ctx->key1, - data+offset, - output+offset, - 0); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 1); - des_ecb_crypt(&ctx->key3, - buf, - output+offset, - 0); - offset += 8; - } - *outlen = len; - if (offset < len) { - *outlen += len - offset; - tmp = offset; - memset(buf, 0, 8); - while (tmp < len) { - buf[i++] = data[tmp]; - tmp++; - } - des_ecb_crypt(&ctx->key1, - buf, - output+offset, - 0); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 1); - des_ecb_crypt(&ctx->key3, - buf, - output+offset, - 0); - } - return 0; -} - -static gint -des3_cbc_encrypt(struct _des3_ctx *ctx, const guchar data[], - size_t len, guchar output[], size_t *outlen) -{ - int offset = 0; - int i = 0; - int tmp; - guint8 buf[8]; - memcpy(buf, ctx->iv, 8); - while (offset + 8 <= len) { - for (i = 0; i < 8; i++) - buf[i] ^= data[offset + i]; - des_ecb_crypt(&ctx->key1, - buf, - output+offset, - 0); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 1); - des_ecb_crypt(&ctx->key3, - buf, - output+offset, - 0); - memcpy(buf, output+offset, 8); - offset += 8; - } - *outlen = len; - if (offset < len) { - *outlen += len - offset; - tmp = offset; - i = 0; - while (tmp < len) { - buf[i++] ^= data[tmp]; - tmp++; - } - des_ecb_crypt(&ctx->key1, - buf, - output+offset, - 0); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 1); - des_ecb_crypt(&ctx->key3, - buf, - output+offset, - 0); - } - return 0; -} - -static gint -des3_encrypt(PurpleCipherContext *context, const guchar data[], - size_t len, guchar output[], size_t *outlen) -{ - struct _des3_ctx *ctx = purple_cipher_context_get_data(context); - - if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_ECB) { - return des3_ecb_encrypt(ctx, data, len, output, outlen); - } else if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_CBC) { - return des3_cbc_encrypt(ctx, data, len, output, outlen); - } else { - g_return_val_if_reached(0); - } - - return 0; -} - -static gint -des3_ecb_decrypt(struct _des3_ctx *ctx, const guchar data[], - size_t len, guchar output[], size_t *outlen) -{ - int offset = 0; - int i = 0; - int tmp; - guint8 buf[8] = {0,0,0,0,0,0,0,0}; - while (offset + 8 <= len) { - /* NOTE: Apply key in reverse */ - des_ecb_crypt(&ctx->key3, - data+offset, - output+offset, - 1); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 0); - des_ecb_crypt(&ctx->key1, - buf, - output+offset, - 1); - offset+=8; - } - *outlen = len; - if (offset < len) { - *outlen += len - offset; - tmp = offset; - memset(buf, 0, 8); - while (tmp < len) { - buf[i++] = data[tmp]; - tmp++; - } - des_ecb_crypt(&ctx->key3, - buf, - output+offset, - 1); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 0); - des_ecb_crypt(&ctx->key1, - buf, - output+offset, - 1); - } - return 0; -} - -static gint -des3_cbc_decrypt(struct _des3_ctx *ctx, const guchar data[], - size_t len, guchar output[], size_t *outlen) -{ - int offset = 0; - int i = 0; - int tmp; - guint8 buf[8] = {0,0,0,0,0,0,0,0}; - guint8 link[8]; - memcpy(link, ctx->iv, 8); - while (offset + 8 <= len) { - des_ecb_crypt(&ctx->key3, - data+offset, - output+offset, - 1); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 0); - des_ecb_crypt(&ctx->key1, - buf, - output+offset, - 1); - for (i = 0; i < 8; i++) - output[offset + i] ^= link[i]; - memcpy(link, data + offset, 8); - offset+=8; - } - *outlen = len; - if(offsetkey3, - buf, - output+offset, - 1); - des_ecb_crypt(&ctx->key2, - output+offset, - buf, - 0); - des_ecb_crypt(&ctx->key1, - buf, - output+offset, - 1); - for (i = 0; i < 8; i++) - output[offset + i] ^= link[i]; - } - return 0; -} - -static gint -des3_decrypt(PurpleCipherContext *context, const guchar data[], - size_t len, guchar output[], size_t *outlen) -{ - struct _des3_ctx *ctx = purple_cipher_context_get_data(context); - - if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_ECB) { - return des3_ecb_decrypt(ctx, data, len, output, outlen); - } else if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_CBC) { - return des3_cbc_decrypt(ctx, data, len, output, outlen); - } else { - g_return_val_if_reached(0); - } - - return 0; -} - -static void -des3_set_batch(PurpleCipherContext *context, PurpleCipherBatchMode mode) -{ - struct _des3_ctx *ctx = purple_cipher_context_get_data(context); - - ctx->mode = mode; -} - -static PurpleCipherBatchMode -des3_get_batch(PurpleCipherContext *context) -{ - struct _des3_ctx *ctx = purple_cipher_context_get_data(context); - - return ctx->mode; -} - -static void -des3_set_iv(PurpleCipherContext *context, guchar *iv, size_t len) -{ - struct _des3_ctx *ctx; - - g_return_if_fail(len == 8); - - ctx = purple_cipher_context_get_data(context); - - memcpy(ctx->iv, iv, len); -} - -static void -des3_init(PurpleCipherContext *context, gpointer extra) -{ - struct _des3_ctx *mctx; - mctx = g_new0(struct _des3_ctx, 1); - purple_cipher_context_set_data(context, mctx); -} - -static void -des3_uninit(PurpleCipherContext *context) -{ - struct _des3_ctx *des3_context; - - des3_context = purple_cipher_context_get_data(context); - memset(des3_context, 0, sizeof(des3_context)); - - g_free(des3_context); - des3_context = NULL; -} - -static PurpleCipherOps DES3Ops = { - NULL, /* Set option */ - NULL, /* Get option */ - des3_init, /* init */ - NULL, /* reset */ - des3_uninit, /* uninit */ - des3_set_iv, /* set iv */ - NULL, /* append */ - NULL, /* digest */ - des3_encrypt, /* encrypt */ - des3_decrypt, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - des3_set_key, /* set key */ - NULL, /* get key size */ - des3_set_batch, /* set batch mode */ - des3_get_batch, /* get batch mode */ - NULL, /* get block size */ - NULL /* set key with len */ -}; - -/******************************************************************************* - * SHA-1 - ******************************************************************************/ -#define SHA1_HMAC_BLOCK_SIZE 64 - -static size_t -sha1_get_block_size(PurpleCipherContext *context) -{ - /* This does not change (in this case) */ - return SHA1_HMAC_BLOCK_SIZE; -} - - -#if GLIB_CHECK_VERSION(2,16,0) - -static void -sha1_init(PurpleCipherContext *context, void *extra) -{ - purple_g_checksum_init(context, G_CHECKSUM_SHA1); -} - -static void -sha1_reset(PurpleCipherContext *context, void *extra) -{ - purple_g_checksum_reset(context, G_CHECKSUM_SHA1); -} - -static gboolean -sha1_digest(PurpleCipherContext *context, gsize in_len, guchar digest[20], - gsize *out_len) -{ - return purple_g_checksum_digest(context, G_CHECKSUM_SHA1, in_len, - digest, out_len); -} - -static PurpleCipherOps SHA1Ops = { - NULL, /* Set Option */ - NULL, /* Get Option */ - sha1_init, /* init */ - sha1_reset, /* reset */ - purple_g_checksum_uninit, /* uninit */ - NULL, /* set iv */ - purple_g_checksum_append, /* append */ - sha1_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - NULL, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - sha1_get_block_size, /* get block size */ - NULL /* set key with len */ -}; - -#else /* GLIB_CHECK_VERSION(2,16,0) */ - -#define SHA1_HMAC_BLOCK_SIZE 64 -#define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF) - -struct SHA1Context { - guint32 H[5]; - guint32 W[80]; - - gint lenW; - - guint32 sizeHi; - guint32 sizeLo; -}; - -static void -sha1_hash_block(struct SHA1Context *sha1_ctx) { - gint i; - guint32 A, B, C, D, E, T; - - for(i = 16; i < 80; i++) { - sha1_ctx->W[i] = SHA1_ROTL(sha1_ctx->W[i - 3] ^ - sha1_ctx->W[i - 8] ^ - sha1_ctx->W[i - 14] ^ - sha1_ctx->W[i - 16], 1); - } - - A = sha1_ctx->H[0]; - B = sha1_ctx->H[1]; - C = sha1_ctx->H[2]; - D = sha1_ctx->H[3]; - E = sha1_ctx->H[4]; - - for(i = 0; i < 20; i++) { - T = (SHA1_ROTL(A, 5) + (((C ^ D) & B) ^ D) + E + sha1_ctx->W[i] + 0x5A827999) & 0xFFFFFFFF; - E = D; - D = C; - C = SHA1_ROTL(B, 30); - B = A; - A = T; - } - - for(i = 20; i < 40; i++) { - T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0x6ED9EBA1) & 0xFFFFFFFF; - E = D; - D = C; - C = SHA1_ROTL(B, 30); - B = A; - A = T; - } - - for(i = 40; i < 60; i++) { - T = (SHA1_ROTL(A, 5) + ((B & C) | (D & (B | C))) + E + sha1_ctx->W[i] + 0x8F1BBCDC) & 0xFFFFFFFF; - E = D; - D = C; - C = SHA1_ROTL(B, 30); - B = A; - A = T; - } - - for(i = 60; i < 80; i++) { - T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0xCA62C1D6) & 0xFFFFFFFF; - E = D; - D = C; - C = SHA1_ROTL(B, 30); - B = A; - A = T; - } - - sha1_ctx->H[0] += A; - sha1_ctx->H[1] += B; - sha1_ctx->H[2] += C; - sha1_ctx->H[3] += D; - sha1_ctx->H[4] += E; -} - -static void -sha1_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { - struct SHA1Context *ctx; - - ctx = purple_cipher_context_get_data(context); - - if(purple_strequal(name, "sizeHi")) { - ctx->sizeHi = GPOINTER_TO_INT(value); - } else if(purple_strequal(name, "sizeLo")) { - ctx->sizeLo = GPOINTER_TO_INT(value); - } else if(purple_strequal(name, "lenW")) { - ctx->lenW = GPOINTER_TO_INT(value); - } -} - -static void * -sha1_get_opt(PurpleCipherContext *context, const gchar *name) { - struct SHA1Context *ctx; - - ctx = purple_cipher_context_get_data(context); - - if(purple_strequal(name, "sizeHi")) { - return GINT_TO_POINTER(ctx->sizeHi); - } else if(purple_strequal(name, "sizeLo")) { - return GINT_TO_POINTER(ctx->sizeLo); - } else if(purple_strequal(name, "lenW")) { - return GINT_TO_POINTER(ctx->lenW); - } - - return NULL; -} - -static void -sha1_init(PurpleCipherContext *context, void *extra) { - struct SHA1Context *sha1_ctx; - - sha1_ctx = g_new0(struct SHA1Context, 1); - - purple_cipher_context_set_data(context, sha1_ctx); - - purple_cipher_context_reset(context, extra); -} - -static void -sha1_reset(PurpleCipherContext *context, void *extra) { - struct SHA1Context *sha1_ctx; - gint i; - - sha1_ctx = purple_cipher_context_get_data(context); - - g_return_if_fail(sha1_ctx); - - sha1_ctx->lenW = 0; - sha1_ctx->sizeHi = 0; - sha1_ctx->sizeLo = 0; - - sha1_ctx->H[0] = 0x67452301; - sha1_ctx->H[1] = 0xEFCDAB89; - sha1_ctx->H[2] = 0x98BADCFE; - sha1_ctx->H[3] = 0x10325476; - sha1_ctx->H[4] = 0xC3D2E1F0; - - for(i = 0; i < 80; i++) - sha1_ctx->W[i] = 0; -} - -static void -sha1_uninit(PurpleCipherContext *context) { - struct SHA1Context *sha1_ctx; - - purple_cipher_context_reset(context, NULL); - - sha1_ctx = purple_cipher_context_get_data(context); - - memset(sha1_ctx, 0, sizeof(struct SHA1Context)); - - g_free(sha1_ctx); - sha1_ctx = NULL; -} - - -static void -sha1_append(PurpleCipherContext *context, const guchar *data, size_t len) { - struct SHA1Context *sha1_ctx; - gint i; - - sha1_ctx = purple_cipher_context_get_data(context); - - g_return_if_fail(sha1_ctx); - - for(i = 0; i < len; i++) { - sha1_ctx->W[sha1_ctx->lenW / 4] <<= 8; - sha1_ctx->W[sha1_ctx->lenW / 4] |= data[i]; - - if((++sha1_ctx->lenW) % 64 == 0) { - sha1_hash_block(sha1_ctx); - sha1_ctx->lenW = 0; - } - - sha1_ctx->sizeLo += 8; - sha1_ctx->sizeHi += (sha1_ctx->sizeLo < 8); - } -} - -static gboolean -sha1_digest(PurpleCipherContext *context, size_t in_len, guchar digest[20], - size_t *out_len) -{ - struct SHA1Context *sha1_ctx; - guchar pad0x80 = 0x80, pad0x00 = 0x00; - guchar padlen[8]; - gint i; - - g_return_val_if_fail(in_len >= 20, FALSE); - - sha1_ctx = purple_cipher_context_get_data(context); - - g_return_val_if_fail(sha1_ctx, FALSE); - - padlen[0] = (guchar)((sha1_ctx->sizeHi >> 24) & 255); - padlen[1] = (guchar)((sha1_ctx->sizeHi >> 16) & 255); - padlen[2] = (guchar)((sha1_ctx->sizeHi >> 8) & 255); - padlen[3] = (guchar)((sha1_ctx->sizeHi >> 0) & 255); - padlen[4] = (guchar)((sha1_ctx->sizeLo >> 24) & 255); - padlen[5] = (guchar)((sha1_ctx->sizeLo >> 16) & 255); - padlen[6] = (guchar)((sha1_ctx->sizeLo >> 8) & 255); - padlen[7] = (guchar)((sha1_ctx->sizeLo >> 0) & 255); - - /* pad with a 1, then zeroes, then length */ - purple_cipher_context_append(context, &pad0x80, 1); - while(sha1_ctx->lenW != 56) - purple_cipher_context_append(context, &pad0x00, 1); - purple_cipher_context_append(context, padlen, 8); - - for(i = 0; i < 20; i++) { - digest[i] = (guchar)(sha1_ctx->H[i / 4] >> 24); - sha1_ctx->H[i / 4] <<= 8; - } - - purple_cipher_context_reset(context, NULL); - - if(out_len) - *out_len = 20; - - return TRUE; -} - -static PurpleCipherOps SHA1Ops = { - sha1_set_opt, /* Set Option */ - sha1_get_opt, /* Get Option */ - sha1_init, /* init */ - sha1_reset, /* reset */ - sha1_uninit, /* uninit */ - NULL, /* set iv */ - sha1_append, /* append */ - sha1_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - NULL, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - sha1_get_block_size, /* get block size */ - NULL /* set key with len */ -}; - -#endif /* GLIB_CHECK_VERSION(2,16,0) */ - -/******************************************************************************* - * SHA-256 - ******************************************************************************/ -#define SHA256_HMAC_BLOCK_SIZE 64 - -static size_t -sha256_get_block_size(PurpleCipherContext *context) -{ - /* This does not change (in this case) */ - return SHA256_HMAC_BLOCK_SIZE; -} - -#if GLIB_CHECK_VERSION(2,16,0) - -static void -sha256_init(PurpleCipherContext *context, void *extra) -{ - purple_g_checksum_init(context, G_CHECKSUM_SHA256); -} - -static void -sha256_reset(PurpleCipherContext *context, void *extra) -{ - purple_g_checksum_reset(context, G_CHECKSUM_SHA256); -} - -static gboolean -sha256_digest(PurpleCipherContext *context, gsize in_len, guchar digest[20], - gsize *out_len) -{ - return purple_g_checksum_digest(context, G_CHECKSUM_SHA256, in_len, - digest, out_len); -} - -static PurpleCipherOps SHA256Ops = { - NULL, /* Set Option */ - NULL, /* Get Option */ - sha256_init, /* init */ - sha256_reset, /* reset */ - purple_g_checksum_uninit, /* uninit */ - NULL, /* set iv */ - purple_g_checksum_append, /* append */ - sha256_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - NULL, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - sha256_get_block_size, /* get block size */ - NULL /* set key with len */ -}; - -#else /* GLIB_CHECK_VERSION(2,16,0) */ - -#define SHA256_ROTR(X,n) ((((X) >> (n)) | ((X) << (32-(n)))) & 0xFFFFFFFF) - -static const guint32 sha256_K[64] = -{ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -struct SHA256Context { - guint32 H[8]; - guint32 W[64]; - - gint lenW; - - guint32 sizeHi; - guint32 sizeLo; -}; - -static void -sha256_hash_block(struct SHA256Context *sha256_ctx) { - gint i; - guint32 A, B, C, D, E, F, G, H, T1, T2; - - for(i = 16; i < 64; i++) { - sha256_ctx->W[i] = - (SHA256_ROTR(sha256_ctx->W[i-2], 17) ^ SHA256_ROTR(sha256_ctx->W[i-2], 19) ^ (sha256_ctx->W[i-2] >> 10)) - + sha256_ctx->W[i-7] - + (SHA256_ROTR(sha256_ctx->W[i-15], 7) ^ SHA256_ROTR(sha256_ctx->W[i-15], 18) ^ (sha256_ctx->W[i-15] >> 3)) - + sha256_ctx->W[i-16]; - } - - A = sha256_ctx->H[0]; - B = sha256_ctx->H[1]; - C = sha256_ctx->H[2]; - D = sha256_ctx->H[3]; - E = sha256_ctx->H[4]; - F = sha256_ctx->H[5]; - G = sha256_ctx->H[6]; - H = sha256_ctx->H[7]; - - for(i = 0; i < 64; i++) { - T1 = H - + (SHA256_ROTR(E, 6) ^ SHA256_ROTR(E, 11) ^ SHA256_ROTR(E, 25)) - + ((E & F) ^ ((~E) & G)) - + sha256_K[i] + sha256_ctx->W[i]; - T2 = (SHA256_ROTR(A, 2) ^ SHA256_ROTR(A, 13) ^ SHA256_ROTR(A, 22)) - + ((A & B) ^ (A & C) ^ (B & C)); - H = G; - G = F; - F = E; - E = D + T1; - D = C; - C = B; - B = A; - A = T1 + T2; - } - - sha256_ctx->H[0] += A; - sha256_ctx->H[1] += B; - sha256_ctx->H[2] += C; - sha256_ctx->H[3] += D; - sha256_ctx->H[4] += E; - sha256_ctx->H[5] += F; - sha256_ctx->H[6] += G; - sha256_ctx->H[7] += H; -} - -static void -sha256_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { - struct SHA256Context *ctx; - - ctx = purple_cipher_context_get_data(context); - - if(!strcmp(name, "sizeHi")) { - ctx->sizeHi = GPOINTER_TO_INT(value); - } else if(!strcmp(name, "sizeLo")) { - ctx->sizeLo = GPOINTER_TO_INT(value); - } else if(!strcmp(name, "lenW")) { - ctx->lenW = GPOINTER_TO_INT(value); - } -} - -static void * -sha256_get_opt(PurpleCipherContext *context, const gchar *name) { - struct SHA256Context *ctx; - - ctx = purple_cipher_context_get_data(context); - - if(!strcmp(name, "sizeHi")) { - return GINT_TO_POINTER(ctx->sizeHi); - } else if(!strcmp(name, "sizeLo")) { - return GINT_TO_POINTER(ctx->sizeLo); - } else if(!strcmp(name, "lenW")) { - return GINT_TO_POINTER(ctx->lenW); - } - - return NULL; -} - -static void -sha256_init(PurpleCipherContext *context, void *extra) { - struct SHA256Context *sha256_ctx; - - sha256_ctx = g_new0(struct SHA256Context, 1); - - purple_cipher_context_set_data(context, sha256_ctx); - - purple_cipher_context_reset(context, extra); -} - -static void -sha256_reset(PurpleCipherContext *context, void *extra) { - struct SHA256Context *sha256_ctx; - gint i; - - sha256_ctx = purple_cipher_context_get_data(context); - - g_return_if_fail(sha256_ctx); - - sha256_ctx->lenW = 0; - sha256_ctx->sizeHi = 0; - sha256_ctx->sizeLo = 0; - - sha256_ctx->H[0] = 0x6a09e667; - sha256_ctx->H[1] = 0xbb67ae85; - sha256_ctx->H[2] = 0x3c6ef372; - sha256_ctx->H[3] = 0xa54ff53a; - sha256_ctx->H[4] = 0x510e527f; - sha256_ctx->H[5] = 0x9b05688c; - sha256_ctx->H[6] = 0x1f83d9ab; - sha256_ctx->H[7] = 0x5be0cd19; - - for(i = 0; i < 64; i++) - sha256_ctx->W[i] = 0; -} - -static void -sha256_uninit(PurpleCipherContext *context) { - struct SHA256Context *sha256_ctx; - - purple_cipher_context_reset(context, NULL); - - sha256_ctx = purple_cipher_context_get_data(context); - - memset(sha256_ctx, 0, sizeof(struct SHA256Context)); - - g_free(sha256_ctx); - sha256_ctx = NULL; -} - - -static void -sha256_append(PurpleCipherContext *context, const guchar *data, size_t len) { - struct SHA256Context *sha256_ctx; - gint i; - - sha256_ctx = purple_cipher_context_get_data(context); - - g_return_if_fail(sha256_ctx); - - for(i = 0; i < len; i++) { - sha256_ctx->W[sha256_ctx->lenW / 4] <<= 8; - sha256_ctx->W[sha256_ctx->lenW / 4] |= data[i]; - - if((++sha256_ctx->lenW) % 64 == 0) { - sha256_hash_block(sha256_ctx); - sha256_ctx->lenW = 0; - } - - sha256_ctx->sizeLo += 8; - sha256_ctx->sizeHi += (sha256_ctx->sizeLo < 8); - } -} - -static gboolean -sha256_digest(PurpleCipherContext *context, size_t in_len, guchar digest[32], - size_t *out_len) -{ - struct SHA256Context *sha256_ctx; - guchar pad0x80 = 0x80, pad0x00 = 0x00; - guchar padlen[8]; - gint i; - - g_return_val_if_fail(in_len >= 32, FALSE); - - sha256_ctx = purple_cipher_context_get_data(context); - - g_return_val_if_fail(sha256_ctx, FALSE); - - padlen[0] = (guchar)((sha256_ctx->sizeHi >> 24) & 255); - padlen[1] = (guchar)((sha256_ctx->sizeHi >> 16) & 255); - padlen[2] = (guchar)((sha256_ctx->sizeHi >> 8) & 255); - padlen[3] = (guchar)((sha256_ctx->sizeHi >> 0) & 255); - padlen[4] = (guchar)((sha256_ctx->sizeLo >> 24) & 255); - padlen[5] = (guchar)((sha256_ctx->sizeLo >> 16) & 255); - padlen[6] = (guchar)((sha256_ctx->sizeLo >> 8) & 255); - padlen[7] = (guchar)((sha256_ctx->sizeLo >> 0) & 255); - - /* pad with a 1, then zeroes, then length */ - purple_cipher_context_append(context, &pad0x80, 1); - while(sha256_ctx->lenW != 56) - purple_cipher_context_append(context, &pad0x00, 1); - purple_cipher_context_append(context, padlen, 8); - - for(i = 0; i < 32; i++) { - digest[i] = (guchar)(sha256_ctx->H[i / 4] >> 24); - sha256_ctx->H[i / 4] <<= 8; - } - - purple_cipher_context_reset(context, NULL); - - if(out_len) - *out_len = 32; - - return TRUE; -} - -static PurpleCipherOps SHA256Ops = { - sha256_set_opt, /* Set Option */ - sha256_get_opt, /* Get Option */ - sha256_init, /* init */ - sha256_reset, /* reset */ - sha256_uninit, /* uninit */ - NULL, /* set iv */ - sha256_append, /* append */ - sha256_digest, /* digest */ - NULL, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - NULL, /* set key */ - NULL, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - sha256_get_block_size, /* get block size */ - NULL /* set key with len */ -}; - -#endif /* GLIB_CHECK_VERSION(2,16,0) */ - -/******************************************************************************* - * RC4 - ******************************************************************************/ - -struct RC4Context { - guchar state[256]; - guchar x; - guchar y; - gint key_len; -}; - -static void -rc4_init(PurpleCipherContext *context, void *extra) { - struct RC4Context *rc4_ctx; - rc4_ctx = g_new0(struct RC4Context, 1); - purple_cipher_context_set_data(context, rc4_ctx); - purple_cipher_context_reset(context, extra); -} - - -static void -rc4_reset(PurpleCipherContext *context, void *extra) { - struct RC4Context *rc4_ctx; - guint i; - - rc4_ctx = purple_cipher_context_get_data(context); - - g_return_if_fail(rc4_ctx); - - for(i = 0; i < 256; i++) - rc4_ctx->state[i] = i; - rc4_ctx->x = 0; - rc4_ctx->y = 0; - - /* default is 5 bytes (40bit key) */ - rc4_ctx->key_len = 5; - -} - -static void -rc4_uninit(PurpleCipherContext *context) { - struct RC4Context *rc4_ctx; - - rc4_ctx = purple_cipher_context_get_data(context); - memset(rc4_ctx, 0, sizeof(rc4_ctx)); - - g_free(rc4_ctx); - rc4_ctx = NULL; -} - - - -static void -rc4_set_key (PurpleCipherContext *context, const guchar * key) { - struct RC4Context *ctx; - guchar *state; - guchar temp_swap; - guchar x, y; - guint i; - - ctx = purple_cipher_context_get_data(context); - - x = 0; - y = 0; - state = &ctx->state[0]; - for(i = 0; i < 256; i++) - { - y = (key[x] + state[i] + y) % 256; - temp_swap = state[i]; - state[i] = state[y]; - state[y] = temp_swap; - x = (x + 1) % ctx->key_len; - } -} - -static void -rc4_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { - struct RC4Context *ctx; - - ctx = purple_cipher_context_get_data(context); - - if(purple_strequal(name, "key_len")) { - ctx->key_len = GPOINTER_TO_INT(value); - } -} - -static size_t -rc4_get_key_size (PurpleCipherContext *context) -{ - struct RC4Context *ctx; - - g_return_val_if_fail(context, -1); - - ctx = purple_cipher_context_get_data(context); - - g_return_val_if_fail(ctx, -1); - - return ctx->key_len; -} - -static void * -rc4_get_opt(PurpleCipherContext *context, const gchar *name) { - struct RC4Context *ctx; - - ctx = purple_cipher_context_get_data(context); - - if(purple_strequal(name, "key_len")) { - return GINT_TO_POINTER(ctx->key_len); - } - - return NULL; -} - -static gint -rc4_encrypt(PurpleCipherContext *context, const guchar data[], - size_t len, guchar output[], size_t *outlen) { - struct RC4Context *ctx; - guchar temp_swap; - guchar x, y, z; - guchar *state; - guint i; - - ctx = purple_cipher_context_get_data(context); - - x = ctx->x; - y = ctx->y; - state = &ctx->state[0]; - - for(i = 0; i < len; i++) - { - x = (x + 1) % 256; - y = (state[x] + y) % 256; - temp_swap = state[x]; - state[x] = state[y]; - state[y] = temp_swap; - z = state[x] + (state[y]) % 256; - output[i] = data[i] ^ state[z]; - } - ctx->x = x; - ctx->y = y; - if(outlen) - *outlen = len; - - return 0; -} - -static PurpleCipherOps RC4Ops = { - rc4_set_opt, /* Set Option */ - rc4_get_opt, /* Get Option */ - rc4_init, /* init */ - rc4_reset, /* reset */ - rc4_uninit, /* uninit */ - NULL, /* set iv */ - NULL, /* append */ - NULL, /* digest */ - rc4_encrypt, /* encrypt */ - NULL, /* decrypt */ - NULL, /* set salt */ - NULL, /* get salt size */ - rc4_set_key, /* set key */ - rc4_get_key_size, /* get key size */ - NULL, /* set batch mode */ - NULL, /* get batch mode */ - NULL, /* get block size */ - NULL /* set key with len */ -}; - /******************************************************************************* * Structs ******************************************************************************/ @@ -2688,6 +223,20 @@ return &handle; } +/* These are implemented in the purple-ciphers sublibrary built in the ciphers + * directory. We could put a header file in there, but it's less hassle for + * the developer to just add it here since they have to register it here as + * well. + */ +PurpleCipherOps *purple_des_cipher_get_ops(); +PurpleCipherOps *purple_des3_cipher_get_ops(); +PurpleCipherOps *purple_hmac_cipher_get_ops(); +PurpleCipherOps *purple_md4_cipher_get_ops(); +PurpleCipherOps *purple_md5_cipher_get_ops(); +PurpleCipherOps *purple_rc4_cipher_get_ops(); +PurpleCipherOps *purple_sha1_cipher_get_ops(); +PurpleCipherOps *purple_sha256_cipher_get_ops(); + void purple_ciphers_init() { gpointer handle; @@ -2703,14 +252,14 @@ purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CIPHER)); - purple_ciphers_register_cipher("md5", &MD5Ops); - purple_ciphers_register_cipher("sha1", &SHA1Ops); - purple_ciphers_register_cipher("sha256", &SHA256Ops); - purple_ciphers_register_cipher("md4", &MD4Ops); - purple_ciphers_register_cipher("hmac", &HMACOps); - purple_ciphers_register_cipher("des", &DESOps); - purple_ciphers_register_cipher("des3", &DES3Ops); - purple_ciphers_register_cipher("rc4", &RC4Ops); + purple_ciphers_register_cipher("md5", purple_md5_cipher_get_ops()); + purple_ciphers_register_cipher("sha1", purple_sha1_cipher_get_ops()); + purple_ciphers_register_cipher("sha256", purple_sha256_cipher_get_ops()); + purple_ciphers_register_cipher("md4", purple_md4_cipher_get_ops()); + purple_ciphers_register_cipher("hmac", purple_hmac_cipher_get_ops()); + purple_ciphers_register_cipher("des", purple_des_cipher_get_ops()); + purple_ciphers_register_cipher("des3", purple_des3_cipher_get_ops()); + purple_ciphers_register_cipher("rc4", purple_rc4_cipher_get_ops()); } void @@ -2729,6 +278,7 @@ purple_signals_unregister_by_instance(purple_ciphers_get_handle()); } + /****************************************************************************** * PurpleCipherContext API *****************************************************************************/ @@ -2828,7 +378,7 @@ if(cipher->ops && cipher->ops->uninit) cipher->ops->uninit(context); - memset(context, 0, sizeof(context)); + memset(context, 0, sizeof(*context)); g_free(context); context = NULL; } diff -r a92f4cb593a4 -r 974722699032 libpurple/cipher.h --- a/libpurple/cipher.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/cipher.h Mon Apr 25 20:13:05 2011 +0000 @@ -28,6 +28,7 @@ #define PURPLE_CIPHER_H #include +#include #define PURPLE_CIPHER(obj) ((PurpleCipher *)(obj)) /**< PurpleCipher typecast helper */ #define PURPLE_CIPHER_OPS(obj) ((PurpleCipherOps *)(obj)) /**< PurpleCipherInfo typecase helper */ @@ -129,9 +130,7 @@ void (*set_key_with_len)(PurpleCipherContext *context, const guchar *key, size_t len); }; -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS /*****************************************************************************/ /** @name PurpleCipher API */ @@ -498,8 +497,6 @@ /*@}*/ -#ifdef __cplusplus -} -#endif /* __cplusplus */ +G_END_DECLS #endif /* PURPLE_CIPHER_H */ diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/Makefile.am Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,17 @@ +noinst_LTLIBRARIES=libpurple-ciphers.la + +libpurple_ciphers_la_SOURCES=\ + des.c \ + gchecksum.c \ + hmac.c \ + md4.c \ + md5.c \ + rc4.c \ + sha1.c \ + sha256.c + +INCLUDES = -I$(top_srcdir)/libpurple + +AM_CPPFLAGS = \ + $(GLIB_CFLAGS) + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/des.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/des.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,846 @@ +/* + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * Original des taken from gpg + * + * des.c - DES and Triple-DES encryption/decryption Algorithm + * Copyright (C) 1998 Free Software Foundation, Inc. + * + * Please see below for more legal information! + * + * According to the definition of DES in FIPS PUB 46-2 from December 1993. + * For a description of triple encryption, see: + * Bruce Schneier: Applied Cryptography. Second Edition. + * John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff. + * + * This file is part of GnuPG. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include + +/****************************************************************************** + * DES + *****************************************************************************/ +typedef struct _des_ctx +{ + guint32 encrypt_subkeys[32]; + guint32 decrypt_subkeys[32]; +} des_ctx[1]; + +/* + * The s-box values are permuted according to the 'primitive function P' + */ +static const guint32 sbox1[64] = +{ + 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000, + 0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002, + 0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202, + 0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000, + 0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200, + 0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202, + 0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200, + 0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002 +}; + +static const guint32 sbox2[64] = +{ + 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010, + 0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010, + 0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000, + 0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010, + 0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000, + 0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000, + 0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010, + 0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000 +}; + +static const guint32 sbox3[64] = +{ + 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100, + 0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104, + 0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104, + 0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000, + 0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000, + 0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004, + 0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004, + 0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100 +}; + +static const guint32 sbox4[64] = +{ + 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000, + 0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000, + 0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040, + 0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040, + 0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000, + 0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040, + 0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040 +}; + +static const guint32 sbox5[64] = +{ + 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000, + 0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000, + 0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080, + 0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080, + 0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080, + 0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000, + 0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000, + 0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080 +}; + +static const guint32 sbox6[64] = +{ + 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000, + 0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008, + 0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008, + 0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000, + 0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008, + 0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000, + 0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008, + 0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008 +}; + +static const guint32 sbox7[64] = +{ + 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400, + 0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401, + 0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001, + 0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400, + 0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001, + 0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400, + 0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401, + 0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001 +}; + +static const guint32 sbox8[64] = +{ + 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000, + 0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020, + 0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800, + 0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000, + 0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820, + 0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820, + 0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000, + 0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800 +}; + + +/* + * * These two tables are part of the 'permuted choice 1' function. + * * In this implementation several speed improvements are done. + * */ +static const guint32 leftkey_swap[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const guint32 rightkey_swap[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + + +/* + * Numbers of left shifts per round for encryption subkey schedule + * To calculate the decryption key scheduling we just reverse the + * ordering of the subkeys so we can omit the table for decryption + * subkey schedule. + */ +static const guint8 encrypt_rotate_tab[16] = +{ + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +/* + * Macro to swap bits across two words + **/ +#define DO_PERMUTATION(a, temp, b, offset, mask) \ + temp = ((a>>offset) ^ b) & mask; \ + b ^= temp; \ + a ^= temp<>31)) ^ *subkey++; \ + to ^= sbox8[ work & 0x3f ]; \ + to ^= sbox6[ (work>>8) & 0x3f ]; \ + to ^= sbox4[ (work>>16) & 0x3f ]; \ + to ^= sbox2[ (work>>24) & 0x3f ]; \ + work = ((from>>3) | (from<<29)) ^ *subkey++; \ + to ^= sbox7[ work & 0x3f ]; \ + to ^= sbox5[ (work>>8) & 0x3f ]; \ + to ^= sbox3[ (work>>16) & 0x3f ]; \ + to ^= sbox1[ (work>>24) & 0x3f ]; + + +/* + * Macros to convert 8 bytes from/to 32bit words + **/ +#define READ_64BIT_DATA(data, left, right) \ + left = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \ + right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7]; + +#define WRITE_64BIT_DATA(data, left, right) \ + data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff; \ + data[2] = (left >> 8) &0xff; data[3] = left &0xff; \ + data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff; \ + data[6] = (right >> 8) &0xff; data[7] = right &0xff; + + +/* + * des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for + * 16 encryption rounds. + * To calculate subkeys for decryption the caller + * have to reorder the generated subkeys. + * + * rawkey: 8 Bytes of key data + * subkey: Array of at least 32 guint32s. Will be filled + * with calculated subkeys. + * + **/ +static void +des_key_schedule (const guint8 * rawkey, guint32 * subkey) +{ + guint32 left, right, work; + int round; + + READ_64BIT_DATA (rawkey, left, right) + + DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f) + DO_PERMUTATION (right, work, left, 0, 0x10101010) + + left = (leftkey_swap[(left >> 0) & 0xf] << 3) | (leftkey_swap[(left >> 8) & 0xf] << 2) + | (leftkey_swap[(left >> 16) & 0xf] << 1) | (leftkey_swap[(left >> 24) & 0xf]) + | (leftkey_swap[(left >> 5) & 0xf] << 7) | (leftkey_swap[(left >> 13) & 0xf] << 6) + | (leftkey_swap[(left >> 21) & 0xf] << 5) | (leftkey_swap[(left >> 29) & 0xf] << 4); + + left &= 0x0fffffff; + + right = (rightkey_swap[(right >> 1) & 0xf] << 3) | (rightkey_swap[(right >> 9) & 0xf] << 2) + | (rightkey_swap[(right >> 17) & 0xf] << 1) | (rightkey_swap[(right >> 25) & 0xf]) + | (rightkey_swap[(right >> 4) & 0xf] << 7) | (rightkey_swap[(right >> 12) & 0xf] << 6) + | (rightkey_swap[(right >> 20) & 0xf] << 5) | (rightkey_swap[(right >> 28) & 0xf] << 4); + + right &= 0x0fffffff; + + for (round = 0; round < 16; ++round) + { + left = ((left << encrypt_rotate_tab[round]) | (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff; + right = ((right << encrypt_rotate_tab[round]) | (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff; + + *subkey++ = ((left << 4) & 0x24000000) + | ((left << 28) & 0x10000000) + | ((left << 14) & 0x08000000) + | ((left << 18) & 0x02080000) + | ((left << 6) & 0x01000000) + | ((left << 9) & 0x00200000) + | ((left >> 1) & 0x00100000) + | ((left << 10) & 0x00040000) + | ((left << 2) & 0x00020000) + | ((left >> 10) & 0x00010000) + | ((right >> 13) & 0x00002000) + | ((right >> 4) & 0x00001000) + | ((right << 6) & 0x00000800) + | ((right >> 1) & 0x00000400) + | ((right >> 14) & 0x00000200) + | (right & 0x00000100) + | ((right >> 5) & 0x00000020) + | ((right >> 10) & 0x00000010) + | ((right >> 3) & 0x00000008) + | ((right >> 18) & 0x00000004) + | ((right >> 26) & 0x00000002) + | ((right >> 24) & 0x00000001); + + *subkey++ = ((left << 15) & 0x20000000) + | ((left << 17) & 0x10000000) + | ((left << 10) & 0x08000000) + | ((left << 22) & 0x04000000) + | ((left >> 2) & 0x02000000) + | ((left << 1) & 0x01000000) + | ((left << 16) & 0x00200000) + | ((left << 11) & 0x00100000) + | ((left << 3) & 0x00080000) + | ((left >> 6) & 0x00040000) + | ((left << 15) & 0x00020000) + | ((left >> 4) & 0x00010000) + | ((right >> 2) & 0x00002000) + | ((right << 8) & 0x00001000) + | ((right >> 14) & 0x00000808) + | ((right >> 9) & 0x00000400) + | ((right) & 0x00000200) + | ((right << 7) & 0x00000100) + | ((right >> 7) & 0x00000020) + | ((right >> 3) & 0x00000011) + | ((right << 2) & 0x00000004) + | ((right >> 21) & 0x00000002); + } +} + + +/* + * Fill a DES context with subkeys calculated from a 64bit key. + * Does not check parity bits, but simply ignore them. + * Does not check for weak keys. + **/ +static void +des_set_key (PurpleCipherContext *context, const guchar * key) +{ + struct _des_ctx *ctx = purple_cipher_context_get_data(context); + int i; + + des_key_schedule (key, ctx->encrypt_subkeys); + + for(i=0; i<32; i+=2) + { + ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i]; + ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i]; + } +} + + +/* + * Electronic Codebook Mode DES encryption/decryption of data according + * to 'mode'. + **/ +static int +des_ecb_crypt (struct _des_ctx *ctx, const guint8 * from, guint8 * to, int mode) +{ + guint32 left, right, work; + guint32 *keys; + + keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys; + + READ_64BIT_DATA (from, left, right) + INITIAL_PERMUTATION (left, work, right) + + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys) + + FINAL_PERMUTATION (right, work, left) + WRITE_64BIT_DATA (to, right, left) + + return 0; +} + +static gint +des_encrypt(PurpleCipherContext *context, const guchar data[], + size_t len, guchar output[], size_t *outlen) +{ + int offset = 0; + int i = 0; + int tmp; + guint8 buf[8] = {0,0,0,0,0,0,0,0}; + while(offset+8<=len) { + des_ecb_crypt(purple_cipher_context_get_data(context), + data+offset, + output+offset, + 0); + offset+=8; + } + *outlen = len; + if(offsetkey1.encrypt_subkeys); + des_key_schedule (key + 8, ctx->key2.encrypt_subkeys); + des_key_schedule (key + 16, ctx->key3.encrypt_subkeys); + + for (i = 0; i < 32; i += 2) + { + ctx->key1.decrypt_subkeys[i] = ctx->key1.encrypt_subkeys[30-i]; + ctx->key1.decrypt_subkeys[i+1] = ctx->key1.encrypt_subkeys[31-i]; + ctx->key2.decrypt_subkeys[i] = ctx->key2.encrypt_subkeys[30-i]; + ctx->key2.decrypt_subkeys[i+1] = ctx->key2.encrypt_subkeys[31-i]; + ctx->key3.decrypt_subkeys[i] = ctx->key3.encrypt_subkeys[30-i]; + ctx->key3.decrypt_subkeys[i+1] = ctx->key3.encrypt_subkeys[31-i]; + } +} + +static gint +des3_ecb_encrypt(struct _des3_ctx *ctx, const guchar data[], + size_t len, guchar output[], size_t *outlen) +{ + int offset = 0; + int i = 0; + int tmp; + guint8 buf[8] = {0,0,0,0,0,0,0,0}; + while (offset + 8 <= len) { + des_ecb_crypt(&ctx->key1, + data+offset, + output+offset, + 0); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 1); + des_ecb_crypt(&ctx->key3, + buf, + output+offset, + 0); + offset += 8; + } + *outlen = len; + if (offset < len) { + *outlen += len - offset; + tmp = offset; + memset(buf, 0, 8); + while (tmp < len) { + buf[i++] = data[tmp]; + tmp++; + } + des_ecb_crypt(&ctx->key1, + buf, + output+offset, + 0); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 1); + des_ecb_crypt(&ctx->key3, + buf, + output+offset, + 0); + } + return 0; +} + +static gint +des3_cbc_encrypt(struct _des3_ctx *ctx, const guchar data[], + size_t len, guchar output[], size_t *outlen) +{ + int offset = 0; + int i = 0; + int tmp; + guint8 buf[8]; + memcpy(buf, ctx->iv, 8); + while (offset + 8 <= len) { + for (i = 0; i < 8; i++) + buf[i] ^= data[offset + i]; + + des_ecb_crypt(&ctx->key1, + buf, + output+offset, + 0); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 1); + des_ecb_crypt(&ctx->key3, + buf, + output+offset, + 0); + memcpy(buf, output+offset, 8); + offset += 8; + } + *outlen = len; + if (offset < len) { + *outlen += len - offset; + tmp = offset; + i = 0; + while (tmp < len) { + buf[i++] ^= data[tmp]; + tmp++; + } + des_ecb_crypt(&ctx->key1, + buf, + output+offset, + 0); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 1); + des_ecb_crypt(&ctx->key3, + buf, + output+offset, + 0); + } + return 0; +} + +static gint +des3_encrypt(PurpleCipherContext *context, const guchar data[], + size_t len, guchar output[], size_t *outlen) +{ + struct _des3_ctx *ctx = purple_cipher_context_get_data(context); + + if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_ECB) { + return des3_ecb_encrypt(ctx, data, len, output, outlen); + } else if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_CBC) { + return des3_cbc_encrypt(ctx, data, len, output, outlen); + } else { + g_return_val_if_reached(0); + } + + return 0; +} + +static gint +des3_ecb_decrypt(struct _des3_ctx *ctx, const guchar data[], + size_t len, guchar output[], size_t *outlen) +{ + int offset = 0; + int i = 0; + int tmp; + guint8 buf[8] = {0,0,0,0,0,0,0,0}; + while (offset + 8 <= len) { + /* NOTE: Apply key in reverse */ + des_ecb_crypt(&ctx->key3, + data+offset, + output+offset, + 1); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 0); + des_ecb_crypt(&ctx->key1, + buf, + output+offset, + 1); + offset+=8; + } + *outlen = len; + if (offset < len) { + *outlen += len - offset; + tmp = offset; + memset(buf, 0, 8); + while (tmp < len) { + buf[i++] = data[tmp]; + tmp++; + } + des_ecb_crypt(&ctx->key3, + buf, + output+offset, + 1); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 0); + des_ecb_crypt(&ctx->key1, + buf, + output+offset, + 1); + } + return 0; +} + +static gint +des3_cbc_decrypt(struct _des3_ctx *ctx, const guchar data[], + size_t len, guchar output[], size_t *outlen) +{ + int offset = 0; + int i = 0; + int tmp; + guint8 buf[8] = {0,0,0,0,0,0,0,0}; + guint8 link[8]; + memcpy(link, ctx->iv, 8); + while (offset + 8 <= len) { + des_ecb_crypt(&ctx->key3, + data+offset, + output+offset, + 1); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 0); + des_ecb_crypt(&ctx->key1, + buf, + output+offset, + 1); + for (i = 0; i < 8; i++) + output[offset + i] ^= link[i]; + memcpy(link, data + offset, 8); + offset+=8; + } + *outlen = len; + if(offsetkey3, + buf, + output+offset, + 1); + des_ecb_crypt(&ctx->key2, + output+offset, + buf, + 0); + des_ecb_crypt(&ctx->key1, + buf, + output+offset, + 1); + for (i = 0; i < 8; i++) + output[offset + i] ^= link[i]; + } + return 0; +} + +static gint +des3_decrypt(PurpleCipherContext *context, const guchar data[], + size_t len, guchar output[], size_t *outlen) +{ + struct _des3_ctx *ctx = purple_cipher_context_get_data(context); + + if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_ECB) { + return des3_ecb_decrypt(ctx, data, len, output, outlen); + } else if (ctx->mode == PURPLE_CIPHER_BATCH_MODE_CBC) { + return des3_cbc_decrypt(ctx, data, len, output, outlen); + } else { + g_return_val_if_reached(0); + } + + return 0; +} + +static void +des3_set_batch(PurpleCipherContext *context, PurpleCipherBatchMode mode) +{ + struct _des3_ctx *ctx = purple_cipher_context_get_data(context); + + ctx->mode = mode; +} + +static PurpleCipherBatchMode +des3_get_batch(PurpleCipherContext *context) +{ + struct _des3_ctx *ctx = purple_cipher_context_get_data(context); + + return ctx->mode; +} + +static void +des3_set_iv(PurpleCipherContext *context, guchar *iv, size_t len) +{ + struct _des3_ctx *ctx; + + g_return_if_fail(len == 8); + + ctx = purple_cipher_context_get_data(context); + + memcpy(ctx->iv, iv, len); +} + +static void +des3_init(PurpleCipherContext *context, gpointer extra) +{ + struct _des3_ctx *mctx; + mctx = g_new0(struct _des3_ctx, 1); + purple_cipher_context_set_data(context, mctx); +} + +static void +des3_uninit(PurpleCipherContext *context) +{ + struct _des3_ctx *des3_context; + + des3_context = purple_cipher_context_get_data(context); + memset(des3_context, 0, sizeof(*des3_context)); + + g_free(des3_context); + des3_context = NULL; +} + +static PurpleCipherOps DES3Ops = { + NULL, /* Set option */ + NULL, /* Get option */ + des3_init, /* init */ + NULL, /* reset */ + des3_uninit, /* uninit */ + des3_set_iv, /* set iv */ + NULL, /* append */ + NULL, /* digest */ + des3_encrypt, /* encrypt */ + des3_decrypt, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + des3_set_key, /* set key */ + NULL, /* get key size */ + des3_set_batch, /* set batch mode */ + des3_get_batch, /* get batch mode */ + NULL, /* get block size */ + NULL /* set key with len */ +}; + +/****************************************************************************** + * Registration + *****************************************************************************/ +PurpleCipherOps * +purple_des_cipher_get_ops(void) { + return &DESOps; +} + +PurpleCipherOps * +purple_des3_cipher_get_ops(void) { + return &DES3Ops; +} + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/gchecksum.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/gchecksum.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,144 @@ +#include + +#if GLIB_CHECK_VERSION(2,16,0) + +static void +purple_g_checksum_init(PurpleCipherContext *context, GChecksumType type) +{ + GChecksum *checksum; + + checksum = g_checksum_new(type); + purple_cipher_context_set_data(context, checksum); +} + +static void +purple_g_checksum_reset(PurpleCipherContext *context, GChecksumType type) +{ + GChecksum *checksum; + + checksum = purple_cipher_context_get_data(context); + g_return_if_fail(checksum != NULL); + +#if GLIB_CHECK_VERSION(2,18,0) + g_checksum_reset(checksum); +#else + g_checksum_free(checksum); + checksum = g_checksum_new(type); + purple_cipher_context_set_data(context, checksum); +#endif +} + +static void +purple_g_checksum_uninit(PurpleCipherContext *context) +{ + GChecksum *checksum; + + checksum = purple_cipher_context_get_data(context); + g_return_if_fail(checksum != NULL); + + g_checksum_free(checksum); +} + +static void +purple_g_checksum_append(PurpleCipherContext *context, const guchar *data, + gsize len) +{ + GChecksum *checksum; + + checksum = purple_cipher_context_get_data(context); + g_return_if_fail(checksum != NULL); + + while (len >= G_MAXSSIZE) { + g_checksum_update(checksum, data, G_MAXSSIZE); + len -= G_MAXSSIZE; + data += G_MAXSSIZE; + } + + if (len) + g_checksum_update(checksum, data, len); +} + +static gboolean +purple_g_checksum_digest(PurpleCipherContext *context, GChecksumType type, + gsize len, guchar *digest, gsize *out_len) +{ + GChecksum *checksum; + const gssize required_length = g_checksum_type_get_length(type); + + checksum = purple_cipher_context_get_data(context); + + g_return_val_if_fail(len >= required_length, FALSE); + g_return_val_if_fail(checksum != NULL, FALSE); + + g_checksum_get_digest(checksum, digest, &len); + + purple_cipher_context_reset(context, NULL); + + if (out_len) + *out_len = len; + + return TRUE; +} + +/****************************************************************************** + * Macros + *****************************************************************************/ +#define PURPLE_G_CHECKSUM_IMPLEMENTATION(lower, camel, type, block_size) \ + static size_t \ + lower##_get_block_size(PurpleCipherContext *context) { \ + return (block_size); \ + } \ + \ + static void \ + lower##_init(PurpleCipherContext *context, gpointer extra) { \ + purple_g_checksum_init(context, (type)); \ + } \ + \ + static void \ + lower##_reset(PurpleCipherContext *context, gpointer extra) { \ + purple_g_checksum_reset(context, (type)); \ + } \ + \ + static gboolean \ + lower##_digest(PurpleCipherContext *context, gsize in_len, \ + guchar digest[], size_t *out_len) \ + { \ + return purple_g_checksum_digest(context, (type), in_len, digest, \ + out_len); \ + } \ + \ + static PurpleCipherOps camel##Ops = { \ + NULL, /* Set option */ \ + NULL, /* Get option */ \ + lower##_init, /* init */ \ + lower##_reset, /* reset */ \ + purple_g_checksum_uninit, /* uninit */ \ + NULL, /* set iv */ \ + purple_g_checksum_append, /* append */ \ + lower##_digest, /* digest */ \ + NULL, /* encrypt */ \ + NULL, /* decrypt */ \ + NULL, /* set salt */ \ + NULL, /* get salt size */ \ + NULL, /* set key */ \ + NULL, /* get key size */ \ + NULL, /* set batch mode */ \ + NULL, /* get batch mode */ \ + lower##_get_block_size, /* get block size */ \ + NULL /* set key with len */ \ + }; \ + \ + PurpleCipherOps * \ + purple_##lower##_cipher_get_ops(void) { \ + return &camel##Ops; \ + } + +/****************************************************************************** + * Macro Expansion + *****************************************************************************/ +PURPLE_G_CHECKSUM_IMPLEMENTATION(md5, MD5, G_CHECKSUM_MD5, 64); +PURPLE_G_CHECKSUM_IMPLEMENTATION(sha1, SHA1, G_CHECKSUM_SHA1, 64); +PURPLE_G_CHECKSUM_IMPLEMENTATION(sha256, SHA256, G_CHECKSUM_SHA256, 64); + +#endif /* GLIB_CHECK_VERSION(2,16,0) */ + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/hmac.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/hmac.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,218 @@ +/* + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include + +#include + +struct HMAC_Context { + PurpleCipherContext *hash; + char *name; + int blocksize; + guchar *opad; +}; + + static void +hmac_init(PurpleCipherContext *context, gpointer extra) +{ + struct HMAC_Context *hctx; + hctx = g_new0(struct HMAC_Context, 1); + purple_cipher_context_set_data(context, hctx); + purple_cipher_context_reset(context, extra); +} + + static void +hmac_reset(PurpleCipherContext *context, gpointer extra) +{ + struct HMAC_Context *hctx; + + hctx = purple_cipher_context_get_data(context); + + g_free(hctx->name); + hctx->name = NULL; + if (hctx->hash) + purple_cipher_context_destroy(hctx->hash); + hctx->hash = NULL; + hctx->blocksize = 0; + g_free(hctx->opad); + hctx->opad = NULL; +} + + static void +hmac_set_opt(PurpleCipherContext *context, const gchar *name, void *value) +{ + struct HMAC_Context *hctx; + + hctx = purple_cipher_context_get_data(context); + + if (purple_strequal(name, "hash")) { + g_free(hctx->name); + if (hctx->hash) + purple_cipher_context_destroy(hctx->hash); + hctx->name = g_strdup((char*)value); + hctx->hash = purple_cipher_context_new_by_name((char *)value, NULL); + hctx->blocksize = purple_cipher_context_get_block_size(hctx->hash); + } +} + + static void * +hmac_get_opt(PurpleCipherContext *context, const gchar *name) +{ + struct HMAC_Context *hctx; + + hctx = purple_cipher_context_get_data(context); + + if (purple_strequal(name, "hash")) { + return hctx->name; + } + + return NULL; +} + + static void +hmac_append(PurpleCipherContext *context, const guchar *data, size_t len) +{ + struct HMAC_Context *hctx = purple_cipher_context_get_data(context); + + g_return_if_fail(hctx->hash != NULL); + + purple_cipher_context_append(hctx->hash, data, len); +} + + static gboolean +hmac_digest(PurpleCipherContext *context, size_t in_len, guchar *out, size_t *out_len) +{ + struct HMAC_Context *hctx = purple_cipher_context_get_data(context); + PurpleCipherContext *hash = hctx->hash; + guchar *inner_hash; + size_t hash_len; + gboolean result; + + g_return_val_if_fail(hash != NULL, FALSE); + + inner_hash = g_malloc(100); /* TODO: Should be enough for now... */ + result = purple_cipher_context_digest(hash, 100, inner_hash, &hash_len); + + purple_cipher_context_reset(hash, NULL); + + purple_cipher_context_append(hash, hctx->opad, hctx->blocksize); + purple_cipher_context_append(hash, inner_hash, hash_len); + + g_free(inner_hash); + + result = result && purple_cipher_context_digest(hash, in_len, out, out_len); + + return result; +} + + static void +hmac_uninit(PurpleCipherContext *context) +{ + struct HMAC_Context *hctx; + + purple_cipher_context_reset(context, NULL); + + hctx = purple_cipher_context_get_data(context); + + g_free(hctx); +} + + static void +hmac_set_key_with_len(PurpleCipherContext *context, const guchar * key, size_t key_len) +{ + struct HMAC_Context *hctx = purple_cipher_context_get_data(context); + int blocksize, i; + guchar *ipad; + guchar *full_key; + + g_return_if_fail(hctx->hash != NULL); + + g_free(hctx->opad); + + blocksize = hctx->blocksize; + ipad = g_malloc(blocksize); + hctx->opad = g_malloc(blocksize); + + if (key_len > blocksize) { + purple_cipher_context_reset(hctx->hash, NULL); + purple_cipher_context_append(hctx->hash, key, key_len); + full_key = g_malloc(100); /* TODO: Should be enough for now... */ + purple_cipher_context_digest(hctx->hash, 100, full_key, &key_len); + } else + full_key = g_memdup(key, key_len); + + if (key_len < blocksize) { + full_key = g_realloc(full_key, blocksize); + memset(full_key + key_len, 0, blocksize - key_len); + } + + for(i = 0; i < blocksize; i++) { + ipad[i] = 0x36 ^ full_key[i]; + hctx->opad[i] = 0x5c ^ full_key[i]; + } + + g_free(full_key); + + purple_cipher_context_reset(hctx->hash, NULL); + purple_cipher_context_append(hctx->hash, ipad, blocksize); + g_free(ipad); +} + + static void +hmac_set_key(PurpleCipherContext *context, const guchar * key) +{ + hmac_set_key_with_len(context, key, strlen((char *)key)); +} + + static size_t +hmac_get_block_size(PurpleCipherContext *context) +{ + struct HMAC_Context *hctx = purple_cipher_context_get_data(context); + + return hctx->blocksize; +} + +static PurpleCipherOps HMACOps = { + hmac_set_opt, /* Set option */ + hmac_get_opt, /* Get option */ + hmac_init, /* init */ + hmac_reset, /* reset */ + hmac_uninit, /* uninit */ + NULL, /* set iv */ + hmac_append, /* append */ + hmac_digest, /* digest */ + NULL, /* encrypt */ + NULL, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + hmac_set_key, /* set key */ + NULL, /* get key size */ + NULL, /* set batch mode */ + NULL, /* get batch mode */ + hmac_get_block_size, /* get block size */ + hmac_set_key_with_len /* set key with len */ +}; + +PurpleCipherOps * +purple_hmac_cipher_get_ops(void) { + return &HMACOps; +} + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/md4.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/md4.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,297 @@ +/* + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * Original md4 taken from linux kernel + * MD4 Message Digest Algorithm (RFC1320). + * + * Implementation derived from Andrew Tridgell and Steve French's + * CIFS MD4 implementation, and the cryptoapi implementation + * originally based on the public domain implementation written + * by Colin Plumb in 1993. + * + * Copyright (c) Andrew Tridgell 1997-1998. + * Modified by Steve French (sfrench@us.ibm.com) 2002 + * Copyright (c) Cryptoapi developers. + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include + +#define MD4_DIGEST_SIZE 16 +#define MD4_HMAC_BLOCK_SIZE 64 +#define MD4_BLOCK_WORDS 16 +#define MD4_HASH_WORDS 4 + +struct MD4_Context { + guint32 hash[MD4_HASH_WORDS]; + guint32 block[MD4_BLOCK_WORDS]; + guint64 byte_count; +}; + +static inline guint32 lshift(guint32 x, unsigned int s) +{ + x &= 0xFFFFFFFF; + return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); +} + +static inline guint32 F(guint32 x, guint32 y, guint32 z) +{ + return (x & y) | ((~x) & z); +} + +static inline guint32 G(guint32 x, guint32 y, guint32 z) +{ + return (x & y) | (x & z) | (y & z); +} + +static inline guint32 H(guint32 x, guint32 y, guint32 z) +{ + return x ^ y ^ z; +} + +#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s)) +#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (guint32)0x5A827999,s)) +#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (guint32)0x6ED9EBA1,s)) + +static inline void le32_to_cpu_array(guint32 *buf, unsigned int words) +{ + while (words--) { + *buf=GUINT_FROM_LE(*buf); + buf++; + } +} + +static inline void cpu_to_le32_array(guint32 *buf, unsigned int words) +{ + while (words--) { + *buf=GUINT_TO_LE(*buf); + buf++; + } +} + +static void md4_transform(guint32 *hash, guint32 const *in) +{ + guint32 a, b, c, d; + + a = hash[0]; + b = hash[1]; + c = hash[2]; + d = hash[3]; + + ROUND1(a, b, c, d, in[0], 3); + ROUND1(d, a, b, c, in[1], 7); + ROUND1(c, d, a, b, in[2], 11); + ROUND1(b, c, d, a, in[3], 19); + ROUND1(a, b, c, d, in[4], 3); + ROUND1(d, a, b, c, in[5], 7); + ROUND1(c, d, a, b, in[6], 11); + ROUND1(b, c, d, a, in[7], 19); + ROUND1(a, b, c, d, in[8], 3); + ROUND1(d, a, b, c, in[9], 7); + ROUND1(c, d, a, b, in[10], 11); + ROUND1(b, c, d, a, in[11], 19); + ROUND1(a, b, c, d, in[12], 3); + ROUND1(d, a, b, c, in[13], 7); + ROUND1(c, d, a, b, in[14], 11); + ROUND1(b, c, d, a, in[15], 19); + + ROUND2(a, b, c, d,in[ 0], 3); + ROUND2(d, a, b, c, in[4], 5); + ROUND2(c, d, a, b, in[8], 9); + ROUND2(b, c, d, a, in[12], 13); + ROUND2(a, b, c, d, in[1], 3); + ROUND2(d, a, b, c, in[5], 5); + ROUND2(c, d, a, b, in[9], 9); + ROUND2(b, c, d, a, in[13], 13); + ROUND2(a, b, c, d, in[2], 3); + ROUND2(d, a, b, c, in[6], 5); + ROUND2(c, d, a, b, in[10], 9); + ROUND2(b, c, d, a, in[14], 13); + ROUND2(a, b, c, d, in[3], 3); + ROUND2(d, a, b, c, in[7], 5); + ROUND2(c, d, a, b, in[11], 9); + ROUND2(b, c, d, a, in[15], 13); + + ROUND3(a, b, c, d,in[ 0], 3); + ROUND3(d, a, b, c, in[8], 9); + ROUND3(c, d, a, b, in[4], 11); + ROUND3(b, c, d, a, in[12], 15); + ROUND3(a, b, c, d, in[2], 3); + ROUND3(d, a, b, c, in[10], 9); + ROUND3(c, d, a, b, in[6], 11); + ROUND3(b, c, d, a, in[14], 15); + ROUND3(a, b, c, d, in[1], 3); + ROUND3(d, a, b, c, in[9], 9); + ROUND3(c, d, a, b, in[5], 11); + ROUND3(b, c, d, a, in[13], 15); + ROUND3(a, b, c, d, in[3], 3); + ROUND3(d, a, b, c, in[11], 9); + ROUND3(c, d, a, b, in[7], 11); + ROUND3(b, c, d, a, in[15], 15); + + hash[0] += a; + hash[1] += b; + hash[2] += c; + hash[3] += d; +} + +static inline void md4_transform_helper(struct MD4_Context *ctx) +{ + le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(guint32)); + md4_transform(ctx->hash, ctx->block); +} + +static void +md4_init(PurpleCipherContext *context, gpointer extra) { + struct MD4_Context *mctx; + mctx = g_new0(struct MD4_Context, 1); + purple_cipher_context_set_data(context, mctx); + purple_cipher_context_reset(context, extra); + + mctx->hash[0] = 0x67452301; + mctx->hash[1] = 0xefcdab89; + mctx->hash[2] = 0x98badcfe; + mctx->hash[3] = 0x10325476; + mctx->byte_count = 0; +} + +static void +md4_reset(PurpleCipherContext *context, gpointer extra) { + struct MD4_Context *mctx; + + mctx = purple_cipher_context_get_data(context); + + mctx->hash[0] = 0x67452301; + mctx->hash[1] = 0xefcdab89; + mctx->hash[2] = 0x98badcfe; + mctx->hash[3] = 0x10325476; + mctx->byte_count = 0; +} + + static void +md4_append(PurpleCipherContext *context, const guchar *data, size_t len) +{ + struct MD4_Context *mctx = purple_cipher_context_get_data(context); + const guint32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); + + mctx->byte_count += len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + return; + } + + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, avail); + + md4_transform_helper(mctx); + data += avail; + len -= avail; + + while (len >= sizeof(mctx->block)) { + memcpy(mctx->block, data, sizeof(mctx->block)); + md4_transform_helper(mctx); + data += sizeof(mctx->block); + len -= sizeof(mctx->block); + } + + memcpy(mctx->block, data, len); +} + + static gboolean +md4_digest(PurpleCipherContext *context, size_t in_len, guchar *out, + size_t *out_len) +{ + struct MD4_Context *mctx = purple_cipher_context_get_data(context); + const unsigned int offset = mctx->byte_count & 0x3f; + char *p = (char *)mctx->block + offset; + int padding = 56 - (offset + 1); + + + if(in_len<16) return FALSE; + if(out_len) *out_len = 16; + *p++ = 0x80; + if (padding < 0) { + memset(p, 0x00, padding + sizeof (guint64)); + md4_transform_helper(mctx); + p = (char *)mctx->block; + padding = 56; + } + + memset(p, 0, padding); + mctx->block[14] = mctx->byte_count << 3; + mctx->block[15] = mctx->byte_count >> 29; + le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - + sizeof(guint64)) / sizeof(guint32)); + md4_transform(mctx->hash, mctx->block); + cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(guint32)); + memcpy(out, mctx->hash, sizeof(mctx->hash)); + memset(mctx, 0, sizeof(*mctx)); + return TRUE; +} + +static void +md4_uninit(PurpleCipherContext *context) { + struct MD4_Context *md4_context; + + purple_cipher_context_reset(context, NULL); + + md4_context = purple_cipher_context_get_data(context); + memset(md4_context, 0, sizeof(*md4_context)); + + g_free(md4_context); + md4_context = NULL; +} + + static size_t +md4_get_block_size(PurpleCipherContext *context) +{ + /* This does not change (in this case) */ + return MD4_HMAC_BLOCK_SIZE; +} + +static PurpleCipherOps MD4Ops = { + NULL, /* Set option */ + NULL, /* Get option */ + md4_init, /* init */ + md4_reset, /* reset */ + md4_uninit, /* uninit */ + NULL, /* set iv */ + md4_append, /* append */ + md4_digest, /* digest */ + NULL, /* encrypt */ + NULL, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + NULL, /* set key */ + NULL, /* get key size */ + NULL, /* set batch mode */ + NULL, /* get batch mode */ + md4_get_block_size, /* get block size */ + NULL /* set key with len */ +}; + +PurpleCipherOps * +purple_md4_cipher_get_ops(void) { + return &MD4Ops; +} + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/md5.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/md5.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,326 @@ +/* + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * Original md5 + * Copyright (C) 2001-2003 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include + +#if !GLIB_CHECK_VERSION(2,16,0) + +#define MD5_HMAC_BLOCK_SIZE 64 + +struct MD5Context { + guint32 total[2]; + guint32 state[4]; + guchar buffer[64]; +}; + +#define MD5_GET_GUINT32(n,b,i) { \ + (n) = ((guint32)(b) [(i) ] ) \ + | ((guint32)(b) [(i) + 1] << 8) \ + | ((guint32)(b) [(i) + 2] << 16) \ + | ((guint32)(b) [(i) + 3] << 24); \ +} +#define MD5_PUT_GUINT32(n,b,i) { \ + (b)[(i) ] = (guchar)((n) ); \ + (b)[(i) + 1] = (guchar)((n) >> 8); \ + (b)[(i) + 2] = (guchar)((n) >> 16); \ + (b)[(i) + 3] = (guchar)((n) >> 24); \ +} + +static size_t +md5_get_block_size(PurpleCipherContext *context) +{ + /* This does not change (in this case) */ + return MD5_HMAC_BLOCK_SIZE; +} + +static void +md5_init(PurpleCipherContext *context, gpointer extra) { + struct MD5Context *md5_context; + + md5_context = g_new0(struct MD5Context, 1); + + purple_cipher_context_set_data(context, md5_context); + + purple_cipher_context_reset(context, extra); +} + +static void +md5_reset(PurpleCipherContext *context, gpointer extra) { + struct MD5Context *md5_context; + + md5_context = purple_cipher_context_get_data(context); + + md5_context->total[0] = 0; + md5_context->total[1] = 0; + + md5_context->state[0] = 0x67452301; + md5_context->state[1] = 0xEFCDAB89; + md5_context->state[2] = 0x98BADCFE; + md5_context->state[3] = 0x10325476; + + memset(md5_context->buffer, 0, sizeof(md5_context->buffer)); +} + +static void +md5_uninit(PurpleCipherContext *context) { + struct MD5Context *md5_context; + + purple_cipher_context_reset(context, NULL); + + md5_context = purple_cipher_context_get_data(context); + memset(md5_context, 0, sizeof(*md5_context)); + + g_free(md5_context); + md5_context = NULL; +} + +static void +md5_process(struct MD5Context *md5_context, const guchar data[64]) { + guint32 X[16], A, B, C, D; + + A = md5_context->state[0]; + B = md5_context->state[1]; + C = md5_context->state[2]; + D = md5_context->state[3]; + + MD5_GET_GUINT32(X[ 0], data, 0); + MD5_GET_GUINT32(X[ 1], data, 4); + MD5_GET_GUINT32(X[ 2], data, 8); + MD5_GET_GUINT32(X[ 3], data, 12); + MD5_GET_GUINT32(X[ 4], data, 16); + MD5_GET_GUINT32(X[ 5], data, 20); + MD5_GET_GUINT32(X[ 6], data, 24); + MD5_GET_GUINT32(X[ 7], data, 28); + MD5_GET_GUINT32(X[ 8], data, 32); + MD5_GET_GUINT32(X[ 9], data, 36); + MD5_GET_GUINT32(X[10], data, 40); + MD5_GET_GUINT32(X[11], data, 44); + MD5_GET_GUINT32(X[12], data, 48); + MD5_GET_GUINT32(X[13], data, 52); + MD5_GET_GUINT32(X[14], data, 56); + MD5_GET_GUINT32(X[15], data, 60); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) +#define P(a,b,c,d,k,s,t) { \ + a += F(b,c,d) + X[k] + t; \ + a = S(a,s) + b; \ +} + + /* first pass */ +#define F(x,y,z) (z ^ (x & (y ^ z))) + P(A, B, C, D, 0, 7, 0xD76AA478); + P(D, A, B, C, 1, 12, 0xE8C7B756); + P(C, D, A, B, 2, 17, 0x242070DB); + P(B, C, D, A, 3, 22, 0xC1BDCEEE); + P(A, B, C, D, 4, 7, 0xF57C0FAF); + P(D, A, B, C, 5, 12, 0x4787C62A); + P(C, D, A, B, 6, 17, 0xA8304613); + P(B, C, D, A, 7, 22, 0xFD469501); + P(A, B, C, D, 8, 7, 0x698098D8); + P(D, A, B, C, 9, 12, 0x8B44F7AF); + P(C, D, A, B, 10, 17, 0xFFFF5BB1); + P(B, C, D, A, 11, 22, 0x895CD7BE); + P(A, B, C, D, 12, 7, 0x6B901122); + P(D, A, B, C, 13, 12, 0xFD987193); + P(C, D, A, B, 14, 17, 0xA679438E); + P(B, C, D, A, 15, 22, 0x49B40821); +#undef F + + /* second pass */ +#define F(x,y,z) (y ^ (z & (x ^ y))) + P(A, B, C, D, 1, 5, 0xF61E2562); + P(D, A, B, C, 6, 9, 0xC040B340); + P(C, D, A, B, 11, 14, 0x265E5A51); + P(B, C, D, A, 0, 20, 0xE9B6C7AA); + P(A, B, C, D, 5, 5, 0xD62F105D); + P(D, A, B, C, 10, 9, 0x02441453); + P(C, D, A, B, 15, 14, 0xD8A1E681); + P(B, C, D, A, 4, 20, 0xE7D3FBC8); + P(A, B, C, D, 9, 5, 0x21E1CDE6); + P(D, A, B, C, 14, 9, 0xC33707D6); + P(C, D, A, B, 3, 14, 0xF4D50D87); + P(B, C, D, A, 8, 20, 0x455A14ED); + P(A, B, C, D, 13, 5, 0xA9E3E905); + P(D, A, B, C, 2, 9, 0xFCEFA3F8); + P(C, D, A, B, 7, 14, 0x676F02D9); + P(B, C, D, A, 12, 20, 0x8D2A4C8A); +#undef F + + /* third pass */ +#define F(x,y,z) (x ^ y ^ z) + P(A, B, C, D, 5, 4, 0xFFFA3942); + P(D, A, B, C, 8, 11, 0x8771F681); + P(C, D, A, B, 11, 16, 0x6D9D6122); + P(B, C, D, A, 14, 23, 0xFDE5380C); + P(A, B, C, D, 1, 4, 0xA4BEEA44); + P(D, A, B, C, 4, 11, 0x4BDECFA9); + P(C, D, A, B, 7, 16, 0xF6BB4B60); + P(B, C, D, A, 10, 23, 0xBEBFBC70); + P(A, B, C, D, 13, 4, 0x289B7EC6); + P(D, A, B, C, 0, 11, 0xEAA127FA); + P(C, D, A, B, 3, 16, 0xD4EF3085); + P(B, C, D, A, 6, 23, 0x04881D05); + P(A, B, C, D, 9, 4, 0xD9D4D039); + P(D, A, B, C, 12, 11, 0xE6DB99E5); + P(C, D, A, B, 15, 16, 0x1FA27CF8); + P(B, C, D, A, 2, 23, 0xC4AC5665); +#undef F + + /* forth pass */ +#define F(x,y,z) (y ^ (x | ~z)) + P(A, B, C, D, 0, 6, 0xF4292244); + P(D, A, B, C, 7, 10, 0x432AFF97); + P(C, D, A, B, 14, 15, 0xAB9423A7); + P(B, C, D, A, 5, 21, 0xFC93A039); + P(A, B, C, D, 12, 6, 0x655B59C3); + P(D, A, B, C, 3, 10, 0x8F0CCC92); + P(C, D, A, B, 10, 15, 0xFFEFF47D); + P(B, C, D, A, 1, 21, 0x85845DD1); + P(A, B, C, D, 8, 6, 0x6FA87E4F); + P(D, A, B, C, 15, 10, 0xFE2CE6E0); + P(C, D, A, B, 6, 15, 0xA3014314); + P(B, C, D, A, 13, 21, 0x4E0811A1); + P(A, B, C, D, 4, 6, 0xF7537E82); + P(D, A, B, C, 11, 10, 0xBD3AF235); + P(C, D, A, B, 2, 15, 0x2AD7D2BB); + P(B, C, D, A, 9, 21, 0xEB86D391); +#undef F +#undef P +#undef S + + md5_context->state[0] += A; + md5_context->state[1] += B; + md5_context->state[2] += C; + md5_context->state[3] += D; + } + +static void +md5_append(PurpleCipherContext *context, const guchar *data, size_t len) { + struct MD5Context *md5_context = NULL; + guint32 left = 0, fill = 0; + + g_return_if_fail(context != NULL); + + md5_context = purple_cipher_context_get_data(context); + g_return_if_fail(md5_context != NULL); + + left = md5_context->total[0] & 0x3F; + fill = 64 - left; + + md5_context->total[0] += len; + md5_context->total[0] &= 0xFFFFFFFF; + + if(md5_context->total[0] < len) + md5_context->total[1]++; + + if(left && len >= fill) { + memcpy((md5_context->buffer + left), data, fill); + md5_process(md5_context, md5_context->buffer); + len -= fill; + data += fill; + left = 0; + } + + while(len >= 64) { + md5_process(md5_context, data); + len -= 64; + data += 64; + } + + if(len) { + memcpy((md5_context->buffer + left), data, len); + } +} + + static gboolean +md5_digest(PurpleCipherContext *context, size_t in_len, guchar digest[16], + size_t *out_len) +{ + struct MD5Context *md5_context = NULL; + guint32 last, pad; + guint32 high, low; + guchar message[8]; + guchar padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + g_return_val_if_fail(in_len >= 16, FALSE); + + md5_context = purple_cipher_context_get_data(context); + + high = (md5_context->total[0] >> 29) + | (md5_context->total[1] << 3); + low = (md5_context->total[0] << 3); + + MD5_PUT_GUINT32(low, message, 0); + MD5_PUT_GUINT32(high, message, 4); + + last = md5_context->total[0] & 0x3F; + pad = (last < 56) ? (56 - last) : (120 - last); + + md5_append(context, padding, pad); + md5_append(context, message, 8); + + MD5_PUT_GUINT32(md5_context->state[0], digest, 0); + MD5_PUT_GUINT32(md5_context->state[1], digest, 4); + MD5_PUT_GUINT32(md5_context->state[2], digest, 8); + MD5_PUT_GUINT32(md5_context->state[3], digest, 12); + + if(out_len) + *out_len = 16; + + return TRUE; +} + +static PurpleCipherOps MD5Ops = { + NULL, /* Set Option */ + NULL, /* Get Option */ + md5_init, /* init */ + md5_reset, /* reset */ + md5_uninit, /* uninit */ + NULL, /* set iv */ + md5_append, /* append */ + md5_digest, /* digest */ + NULL, /* encrypt */ + NULL, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + NULL, /* set key */ + NULL, /* get key size */ + NULL, /* set batch mode */ + NULL, /* get batch mode */ + md5_get_block_size, /* get block size */ + NULL /* set key with len */ +}; + +PurpleCipherOps * +purple_md5_cipher_get_ops(void) { + return &MD5Ops; +} + +#endif /* !GLIB_CHECK_VERSION(2,16,0) */ + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/rc4.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/rc4.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,192 @@ +/* + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include +#include + +struct RC4Context { + guchar state[256]; + guchar x; + guchar y; + gint key_len; +}; + +static void +rc4_init(PurpleCipherContext *context, void *extra) { + struct RC4Context *rc4_ctx; + rc4_ctx = g_new0(struct RC4Context, 1); + purple_cipher_context_set_data(context, rc4_ctx); + purple_cipher_context_reset(context, extra); +} + + +static void +rc4_reset(PurpleCipherContext *context, void *extra) { + struct RC4Context *rc4_ctx; + guint i; + + rc4_ctx = purple_cipher_context_get_data(context); + + g_return_if_fail(rc4_ctx); + + for(i = 0; i < 256; i++) + rc4_ctx->state[i] = i; + rc4_ctx->x = 0; + rc4_ctx->y = 0; + + /* default is 5 bytes (40bit key) */ + rc4_ctx->key_len = 5; + +} + +static void +rc4_uninit(PurpleCipherContext *context) { + struct RC4Context *rc4_ctx; + + rc4_ctx = purple_cipher_context_get_data(context); + memset(rc4_ctx, 0, sizeof(*rc4_ctx)); + + g_free(rc4_ctx); + rc4_ctx = NULL; +} + + + +static void +rc4_set_key (PurpleCipherContext *context, const guchar * key) { + struct RC4Context *ctx; + guchar *state; + guchar temp_swap; + guchar x, y; + guint i; + + ctx = purple_cipher_context_get_data(context); + + x = 0; + y = 0; + state = &ctx->state[0]; + for(i = 0; i < 256; i++) + { + y = (key[x] + state[i] + y) % 256; + temp_swap = state[i]; + state[i] = state[y]; + state[y] = temp_swap; + x = (x + 1) % ctx->key_len; + } +} + +static void +rc4_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { + struct RC4Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(purple_strequal(name, "key_len")) { + ctx->key_len = GPOINTER_TO_INT(value); + } +} + +static size_t +rc4_get_key_size (PurpleCipherContext *context) +{ + struct RC4Context *ctx; + + g_return_val_if_fail(context, -1); + + ctx = purple_cipher_context_get_data(context); + + g_return_val_if_fail(ctx, -1); + + return ctx->key_len; +} + +static void * +rc4_get_opt(PurpleCipherContext *context, const gchar *name) { + struct RC4Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(purple_strequal(name, "key_len")) { + return GINT_TO_POINTER(ctx->key_len); + } + + return NULL; +} + +static gint +rc4_encrypt(PurpleCipherContext *context, const guchar data[], + size_t len, guchar output[], size_t *outlen) { + struct RC4Context *ctx; + guchar temp_swap; + guchar x, y, z; + guchar *state; + guint i; + + ctx = purple_cipher_context_get_data(context); + + x = ctx->x; + y = ctx->y; + state = &ctx->state[0]; + + for(i = 0; i < len; i++) + { + x = (x + 1) % 256; + y = (state[x] + y) % 256; + temp_swap = state[x]; + state[x] = state[y]; + state[y] = temp_swap; + z = state[x] + (state[y]) % 256; + output[i] = data[i] ^ state[z]; + } + ctx->x = x; + ctx->y = y; + if(outlen) + *outlen = len; + + return 0; +} + +static PurpleCipherOps RC4Ops = { + rc4_set_opt, /* Set Option */ + rc4_get_opt, /* Get Option */ + rc4_init, /* init */ + rc4_reset, /* reset */ + rc4_uninit, /* uninit */ + NULL, /* set iv */ + NULL, /* append */ + NULL, /* digest */ + rc4_encrypt, /* encrypt */ + NULL, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + rc4_set_key, /* set key */ + rc4_get_key_size, /* get key size */ + NULL, /* set batch mode */ + NULL, /* get batch mode */ + NULL, /* get block size */ + NULL /* set key with len */ +}; + +PurpleCipherOps * +purple_rc4_cipher_get_ops(void) { + return &RC4Ops; +} + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/sha1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/sha1.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,281 @@ +/* + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include +#include + +#if !GLIB_CHECK_VERSION(2,16,0) + +#define SHA1_HMAC_BLOCK_SIZE 64 +#define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF) + +struct SHA1Context { + guint32 H[5]; + guint32 W[80]; + + gint lenW; + + guint32 sizeHi; + guint32 sizeLo; +}; + +static size_t +sha1_get_block_size(PurpleCipherContext *context) +{ + /* This does not change (in this case) */ + return SHA1_HMAC_BLOCK_SIZE; +} + +static void +sha1_hash_block(struct SHA1Context *sha1_ctx) { + gint i; + guint32 A, B, C, D, E, T; + + for(i = 16; i < 80; i++) { + sha1_ctx->W[i] = SHA1_ROTL(sha1_ctx->W[i - 3] ^ + sha1_ctx->W[i - 8] ^ + sha1_ctx->W[i - 14] ^ + sha1_ctx->W[i - 16], 1); + } + + A = sha1_ctx->H[0]; + B = sha1_ctx->H[1]; + C = sha1_ctx->H[2]; + D = sha1_ctx->H[3]; + E = sha1_ctx->H[4]; + + for(i = 0; i < 20; i++) { + T = (SHA1_ROTL(A, 5) + (((C ^ D) & B) ^ D) + E + sha1_ctx->W[i] + 0x5A827999) & 0xFFFFFFFF; + E = D; + D = C; + C = SHA1_ROTL(B, 30); + B = A; + A = T; + } + + for(i = 20; i < 40; i++) { + T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0x6ED9EBA1) & 0xFFFFFFFF; + E = D; + D = C; + C = SHA1_ROTL(B, 30); + B = A; + A = T; + } + + for(i = 40; i < 60; i++) { + T = (SHA1_ROTL(A, 5) + ((B & C) | (D & (B | C))) + E + sha1_ctx->W[i] + 0x8F1BBCDC) & 0xFFFFFFFF; + E = D; + D = C; + C = SHA1_ROTL(B, 30); + B = A; + A = T; + } + + for(i = 60; i < 80; i++) { + T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0xCA62C1D6) & 0xFFFFFFFF; + E = D; + D = C; + C = SHA1_ROTL(B, 30); + B = A; + A = T; + } + + sha1_ctx->H[0] += A; + sha1_ctx->H[1] += B; + sha1_ctx->H[2] += C; + sha1_ctx->H[3] += D; + sha1_ctx->H[4] += E; +} + +static void +sha1_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { + struct SHA1Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(purple_strequal(name, "sizeHi")) { + ctx->sizeHi = GPOINTER_TO_INT(value); + } else if(purple_strequal(name, "sizeLo")) { + ctx->sizeLo = GPOINTER_TO_INT(value); + } else if(purple_strequal(name, "lenW")) { + ctx->lenW = GPOINTER_TO_INT(value); + } +} + +static void * +sha1_get_opt(PurpleCipherContext *context, const gchar *name) { + struct SHA1Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(purple_strequal(name, "sizeHi")) { + return GINT_TO_POINTER(ctx->sizeHi); + } else if(purple_strequal(name, "sizeLo")) { + return GINT_TO_POINTER(ctx->sizeLo); + } else if(purple_strequal(name, "lenW")) { + return GINT_TO_POINTER(ctx->lenW); + } + + return NULL; +} + +static void +sha1_init(PurpleCipherContext *context, void *extra) { + struct SHA1Context *sha1_ctx; + + sha1_ctx = g_new0(struct SHA1Context, 1); + + purple_cipher_context_set_data(context, sha1_ctx); + + purple_cipher_context_reset(context, extra); +} + +static void +sha1_reset(PurpleCipherContext *context, void *extra) { + struct SHA1Context *sha1_ctx; + gint i; + + sha1_ctx = purple_cipher_context_get_data(context); + + g_return_if_fail(sha1_ctx); + + sha1_ctx->lenW = 0; + sha1_ctx->sizeHi = 0; + sha1_ctx->sizeLo = 0; + + sha1_ctx->H[0] = 0x67452301; + sha1_ctx->H[1] = 0xEFCDAB89; + sha1_ctx->H[2] = 0x98BADCFE; + sha1_ctx->H[3] = 0x10325476; + sha1_ctx->H[4] = 0xC3D2E1F0; + + for(i = 0; i < 80; i++) + sha1_ctx->W[i] = 0; +} + +static void +sha1_uninit(PurpleCipherContext *context) { + struct SHA1Context *sha1_ctx; + + purple_cipher_context_reset(context, NULL); + + sha1_ctx = purple_cipher_context_get_data(context); + + memset(sha1_ctx, 0, sizeof(struct SHA1Context)); + + g_free(sha1_ctx); + sha1_ctx = NULL; +} + +static void +sha1_append(PurpleCipherContext *context, const guchar *data, size_t len) { + struct SHA1Context *sha1_ctx; + gint i; + + sha1_ctx = purple_cipher_context_get_data(context); + + g_return_if_fail(sha1_ctx); + + for(i = 0; i < len; i++) { + sha1_ctx->W[sha1_ctx->lenW / 4] <<= 8; + sha1_ctx->W[sha1_ctx->lenW / 4] |= data[i]; + + if((++sha1_ctx->lenW) % 64 == 0) { + sha1_hash_block(sha1_ctx); + sha1_ctx->lenW = 0; + } + + sha1_ctx->sizeLo += 8; + sha1_ctx->sizeHi += (sha1_ctx->sizeLo < 8); + } +} + +static gboolean +sha1_digest(PurpleCipherContext *context, size_t in_len, guchar digest[20], + size_t *out_len) +{ + struct SHA1Context *sha1_ctx; + guchar pad0x80 = 0x80, pad0x00 = 0x00; + guchar padlen[8]; + gint i; + + g_return_val_if_fail(in_len >= 20, FALSE); + + sha1_ctx = purple_cipher_context_get_data(context); + + g_return_val_if_fail(sha1_ctx, FALSE); + + padlen[0] = (guchar)((sha1_ctx->sizeHi >> 24) & 255); + padlen[1] = (guchar)((sha1_ctx->sizeHi >> 16) & 255); + padlen[2] = (guchar)((sha1_ctx->sizeHi >> 8) & 255); + padlen[3] = (guchar)((sha1_ctx->sizeHi >> 0) & 255); + padlen[4] = (guchar)((sha1_ctx->sizeLo >> 24) & 255); + padlen[5] = (guchar)((sha1_ctx->sizeLo >> 16) & 255); + padlen[6] = (guchar)((sha1_ctx->sizeLo >> 8) & 255); + padlen[7] = (guchar)((sha1_ctx->sizeLo >> 0) & 255); + + /* pad with a 1, then zeroes, then length */ + purple_cipher_context_append(context, &pad0x80, 1); + while(sha1_ctx->lenW != 56) + purple_cipher_context_append(context, &pad0x00, 1); + purple_cipher_context_append(context, padlen, 8); + + for(i = 0; i < 20; i++) { + digest[i] = (guchar)(sha1_ctx->H[i / 4] >> 24); + sha1_ctx->H[i / 4] <<= 8; + } + + purple_cipher_context_reset(context, NULL); + + if(out_len) + *out_len = 20; + + return TRUE; +} + +static PurpleCipherOps SHA1Ops = { + sha1_set_opt, /* Set Option */ + sha1_get_opt, /* Get Option */ + sha1_init, /* init */ + sha1_reset, /* reset */ + sha1_uninit, /* uninit */ + NULL, /* set iv */ + sha1_append, /* append */ + sha1_digest, /* digest */ + NULL, /* encrypt */ + NULL, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + NULL, /* set key */ + NULL, /* get key size */ + NULL, /* set batch mode */ + NULL, /* get batch mode */ + sha1_get_block_size, /* get block size */ + NULL /* set key with len */ +}; + +PurpleCipherOps * +purple_sha1_cipher_get_ops(void) { + return &SHA1Ops; +} + +#endif /* !GLIB_CHECK_VERSION(2,16,0) */ + diff -r a92f4cb593a4 -r 974722699032 libpurple/ciphers/sha256.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/ciphers/sha256.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,283 @@ +/* + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ +#include + +#if !GLIB_CHECK_VERSION(2,16,0) + +#define SHA256_HMAC_BLOCK_SIZE 64 +#define SHA256_ROTR(X,n) ((((X) >> (n)) | ((X) << (32-(n)))) & 0xFFFFFFFF) + +static const guint32 sha256_K[64] = +{ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +struct SHA256Context { + guint32 H[8]; + guint32 W[64]; + + gint lenW; + + guint32 sizeHi; + guint32 sizeLo; +}; + +static size_t +sha256_get_block_size(PurpleCipherContext *context) +{ + /* This does not change (in this case) */ + return SHA256_HMAC_BLOCK_SIZE; +} + +static void +sha256_hash_block(struct SHA256Context *sha256_ctx) { + gint i; + guint32 A, B, C, D, E, F, G, H, T1, T2; + + for(i = 16; i < 64; i++) { + sha256_ctx->W[i] = + (SHA256_ROTR(sha256_ctx->W[i-2], 17) ^ SHA256_ROTR(sha256_ctx->W[i-2], 19) ^ (sha256_ctx->W[i-2] >> 10)) + + sha256_ctx->W[i-7] + + (SHA256_ROTR(sha256_ctx->W[i-15], 7) ^ SHA256_ROTR(sha256_ctx->W[i-15], 18) ^ (sha256_ctx->W[i-15] >> 3)) + + sha256_ctx->W[i-16]; + } + + A = sha256_ctx->H[0]; + B = sha256_ctx->H[1]; + C = sha256_ctx->H[2]; + D = sha256_ctx->H[3]; + E = sha256_ctx->H[4]; + F = sha256_ctx->H[5]; + G = sha256_ctx->H[6]; + H = sha256_ctx->H[7]; + + for(i = 0; i < 64; i++) { + T1 = H + + (SHA256_ROTR(E, 6) ^ SHA256_ROTR(E, 11) ^ SHA256_ROTR(E, 25)) + + ((E & F) ^ ((~E) & G)) + + sha256_K[i] + sha256_ctx->W[i]; + T2 = (SHA256_ROTR(A, 2) ^ SHA256_ROTR(A, 13) ^ SHA256_ROTR(A, 22)) + + ((A & B) ^ (A & C) ^ (B & C)); + H = G; + G = F; + F = E; + E = D + T1; + D = C; + C = B; + B = A; + A = T1 + T2; + } + + sha256_ctx->H[0] += A; + sha256_ctx->H[1] += B; + sha256_ctx->H[2] += C; + sha256_ctx->H[3] += D; + sha256_ctx->H[4] += E; + sha256_ctx->H[5] += F; + sha256_ctx->H[6] += G; + sha256_ctx->H[7] += H; +} + +static void +sha256_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { + struct SHA256Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(!strcmp(name, "sizeHi")) { + ctx->sizeHi = GPOINTER_TO_INT(value); + } else if(!strcmp(name, "sizeLo")) { + ctx->sizeLo = GPOINTER_TO_INT(value); + } else if(!strcmp(name, "lenW")) { + ctx->lenW = GPOINTER_TO_INT(value); + } +} + +static void * +sha256_get_opt(PurpleCipherContext *context, const gchar *name) { + struct SHA256Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(!strcmp(name, "sizeHi")) { + return GINT_TO_POINTER(ctx->sizeHi); + } else if(!strcmp(name, "sizeLo")) { + return GINT_TO_POINTER(ctx->sizeLo); + } else if(!strcmp(name, "lenW")) { + return GINT_TO_POINTER(ctx->lenW); + } + + return NULL; +} + +static void +sha256_init(PurpleCipherContext *context, void *extra) { + struct SHA256Context *sha256_ctx; + + sha256_ctx = g_new0(struct SHA256Context, 1); + + purple_cipher_context_set_data(context, sha256_ctx); + + purple_cipher_context_reset(context, extra); +} + +static void +sha256_reset(PurpleCipherContext *context, void *extra) { + struct SHA256Context *sha256_ctx; + gint i; + + sha256_ctx = purple_cipher_context_get_data(context); + + g_return_if_fail(sha256_ctx); + + sha256_ctx->lenW = 0; + sha256_ctx->sizeHi = 0; + sha256_ctx->sizeLo = 0; + + sha256_ctx->H[0] = 0x6a09e667; + sha256_ctx->H[1] = 0xbb67ae85; + sha256_ctx->H[2] = 0x3c6ef372; + sha256_ctx->H[3] = 0xa54ff53a; + sha256_ctx->H[4] = 0x510e527f; + sha256_ctx->H[5] = 0x9b05688c; + sha256_ctx->H[6] = 0x1f83d9ab; + sha256_ctx->H[7] = 0x5be0cd19; + + for(i = 0; i < 64; i++) + sha256_ctx->W[i] = 0; +} + +static void +sha256_uninit(PurpleCipherContext *context) { + struct SHA256Context *sha256_ctx; + + purple_cipher_context_reset(context, NULL); + + sha256_ctx = purple_cipher_context_get_data(context); + + memset(sha256_ctx, 0, sizeof(struct SHA256Context)); + + g_free(sha256_ctx); + sha256_ctx = NULL; +} + +static void +sha256_append(PurpleCipherContext *context, const guchar *data, size_t len) { + struct SHA256Context *sha256_ctx; + gint i; + + sha256_ctx = purple_cipher_context_get_data(context); + + g_return_if_fail(sha256_ctx); + + for(i = 0; i < len; i++) { + sha256_ctx->W[sha256_ctx->lenW / 4] <<= 8; + sha256_ctx->W[sha256_ctx->lenW / 4] |= data[i]; + + if((++sha256_ctx->lenW) % 64 == 0) { + sha256_hash_block(sha256_ctx); + sha256_ctx->lenW = 0; + } + + sha256_ctx->sizeLo += 8; + sha256_ctx->sizeHi += (sha256_ctx->sizeLo < 8); + } +} + +static gboolean +sha256_digest(PurpleCipherContext *context, size_t in_len, guchar digest[32], + size_t *out_len) +{ + struct SHA256Context *sha256_ctx; + guchar pad0x80 = 0x80, pad0x00 = 0x00; + guchar padlen[8]; + gint i; + + g_return_val_if_fail(in_len >= 32, FALSE); + + sha256_ctx = purple_cipher_context_get_data(context); + + g_return_val_if_fail(sha256_ctx, FALSE); + + padlen[0] = (guchar)((sha256_ctx->sizeHi >> 24) & 255); + padlen[1] = (guchar)((sha256_ctx->sizeHi >> 16) & 255); + padlen[2] = (guchar)((sha256_ctx->sizeHi >> 8) & 255); + padlen[3] = (guchar)((sha256_ctx->sizeHi >> 0) & 255); + padlen[4] = (guchar)((sha256_ctx->sizeLo >> 24) & 255); + padlen[5] = (guchar)((sha256_ctx->sizeLo >> 16) & 255); + padlen[6] = (guchar)((sha256_ctx->sizeLo >> 8) & 255); + padlen[7] = (guchar)((sha256_ctx->sizeLo >> 0) & 255); + + /* pad with a 1, then zeroes, then length */ + purple_cipher_context_append(context, &pad0x80, 1); + while(sha256_ctx->lenW != 56) + purple_cipher_context_append(context, &pad0x00, 1); + purple_cipher_context_append(context, padlen, 8); + + for(i = 0; i < 32; i++) { + digest[i] = (guchar)(sha256_ctx->H[i / 4] >> 24); + sha256_ctx->H[i / 4] <<= 8; + } + + purple_cipher_context_reset(context, NULL); + + if(out_len) + *out_len = 32; + + return TRUE; +} + +static PurpleCipherOps SHA256Ops = { + sha256_set_opt, /* Set Option */ + sha256_get_opt, /* Get Option */ + sha256_init, /* init */ + sha256_reset, /* reset */ + sha256_uninit, /* uninit */ + NULL, /* set iv */ + sha256_append, /* append */ + sha256_digest, /* digest */ + NULL, /* encrypt */ + NULL, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + NULL, /* set key */ + NULL, /* get key size */ + NULL, /* set batch mode */ + NULL, /* get batch mode */ + sha256_get_block_size, /* get block size */ + NULL /* set key with len */ +}; + +PurpleCipherOps * +purple_sha256_cipher_get_ops(void) { + return &SHA256Ops; +} + +#endif /* !GLIB_CHECK_VERSION(2,16,0) */ + diff -r a92f4cb593a4 -r 974722699032 libpurple/conversation.c --- a/libpurple/conversation.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/conversation.c Mon Apr 25 20:13:05 2011 +0000 @@ -999,12 +999,6 @@ } } - if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { - if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) { - purple_conv_im_set_typing_state(PURPLE_CONV_IM(conv), PURPLE_NOT_TYPING); - } - } - if (ops && ops->write_conv) ops->write_conv(conv, who, alias, displayed, flags, mtime); @@ -1224,6 +1218,10 @@ c = purple_conv_im_get_conversation(im); + if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) { + purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING); + } + /* Pass this on to either the ops structure or the default write func. */ if (c->ui_ops != NULL && c->ui_ops->write_im != NULL) c->ui_ops->write_im(c, who, message, flags, mtime); @@ -2137,6 +2135,8 @@ cb->name = g_strdup(name); cb->flags = flags; cb->alias = g_strdup(alias); + cb->attributes = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); PURPLE_DBUS_REGISTER_POINTER(cb, PurpleConvChatBuddy); return cb; @@ -2169,6 +2169,7 @@ g_free(cb->alias); g_free(cb->alias_key); g_free(cb->name); + g_hash_table_destroy(cb->attributes); PURPLE_DBUS_UNREGISTER_POINTER(cb); g_free(cb); @@ -2182,6 +2183,76 @@ return cb->name; } +const char * +purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy *cb, const char *key) +{ + g_return_val_if_fail(cb != NULL, NULL); + g_return_val_if_fail(key != NULL, NULL); + + return g_hash_table_lookup(cb->attributes, key); +} + +static void +append_attribute_key(gpointer key, gpointer value, gpointer user_data) +{ + GList **list = user_data; + *list = g_list_prepend(*list, key); +} + +GList * +purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy *cb) +{ + GList *keys = NULL; + + g_return_val_if_fail(cb != NULL, NULL); + + g_hash_table_foreach(cb->attributes, (GHFunc)append_attribute_key, &keys); + + return keys; +} + +void +purple_conv_chat_cb_set_attribute(PurpleConvChat *chat, PurpleConvChatBuddy *cb, const char *key, const char *value) +{ + PurpleConversation *conv; + PurpleConversationUiOps *ops; + + g_return_if_fail(cb != NULL); + g_return_if_fail(key != NULL); + g_return_if_fail(value != NULL); + + g_hash_table_replace(cb->attributes, g_strdup(key), g_strdup(value)); + + conv = purple_conv_chat_get_conversation(chat); + ops = purple_conversation_get_ui_ops(conv); + + if (ops != NULL && ops->chat_update_user != NULL) + ops->chat_update_user(conv, cb->name); +} + +void +purple_conv_chat_cb_set_attributes(PurpleConvChat *chat, PurpleConvChatBuddy *cb, GList *keys, GList *values) +{ + PurpleConversation *conv; + PurpleConversationUiOps *ops; + + g_return_if_fail(cb != NULL); + g_return_if_fail(keys != NULL); + g_return_if_fail(values != NULL); + + while (keys != NULL && values != NULL) { + g_hash_table_replace(cb->attributes, g_strdup(keys->data), g_strdup(values->data)); + keys = g_list_next(keys); + values = g_list_next(values); + } + + conv = purple_conv_chat_get_conversation(chat); + ops = purple_conversation_get_ui_ops(conv); + + if (ops != NULL && ops->chat_update_user != NULL) + ops->chat_update_user(conv, cb->name); +} + GList * purple_conversation_get_extended_menu(PurpleConversation *conv) { diff -r a92f4cb593a4 -r 974722699032 libpurple/conversation.h --- a/libpurple/conversation.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/conversation.h Mon Apr 25 20:13:05 2011 +0000 @@ -139,7 +139,8 @@ PURPLE_CBFLAGS_HALFOP = 0x0002, /**< Half-op */ PURPLE_CBFLAGS_OP = 0x0004, /**< Channel Op or Moderator */ PURPLE_CBFLAGS_FOUNDER = 0x0008, /**< Channel Founder */ - PURPLE_CBFLAGS_TYPING = 0x0010 /**< Currently typing */ + PURPLE_CBFLAGS_TYPING = 0x0010, /**< Currently typing */ + PURPLE_CBFLAGS_AWAY = 0x0020 /**< Currently away. @since 2.8.0 */ } PurpleConvChatBuddyFlags; @@ -300,6 +301,9 @@ PurpleConvChatBuddyFlags flags; /**< A bitwise OR of flags for this participant, * such as whether they are a channel operator. */ + GHashTable *attributes; /**< A hash table of attributes about the user, such as + * real name, user@host, etc. + */ }; /** @@ -513,6 +517,46 @@ const char *purple_conversation_get_name(const PurpleConversation *conv); /** + * Get an attribute of a chat buddy + * + * @param cb The chat buddy. + * @param key The key of the attribute. + * + * @return The value of the attribute key. + */ +const char *purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy *cb, const char *key); + +/** + * Get the keys of all atributes of a chat buddy + * + * @param cb The chat buddy. + * + * @return A list of the attributes of a chat buddy. + */ +GList *purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy *cb); + +/** + * Set an attribute of a chat buddy + * + * @param chat The chat. + * @param cb The chat buddy. + * @param key The key of the attribute. + * @param value The value of the attribute. + */ +void purple_conv_chat_cb_set_attribute(PurpleConvChat *chat, PurpleConvChatBuddy *cb, const char *key, const char *value); + +/** + * Set attributes of a chat buddy + * + * @param chat The chat. + * @param cb The chat buddy. + * @param keys A GList of the keys. + * @param values A GList of the values. + */ +void +purple_conv_chat_cb_set_attributes(PurpleConvChat *chat, PurpleConvChatBuddy *cb, GList *keys, GList *values); + +/** * Enables or disables logging for this conversation. * * @param conv The conversation. diff -r a92f4cb593a4 -r 974722699032 libpurple/ft.c --- a/libpurple/ft.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/ft.c Mon Apr 25 20:13:05 2011 +0000 @@ -1100,9 +1100,11 @@ r = write(xfer->fd, buffer, s); if (r < 0 && errno == EAGAIN) r = 0; - if ((purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer)) - purple_xfer_set_completed(xfer, TRUE); } + if (r >= 0 && (purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer) && + !purple_xfer_is_completed(xfer)) + purple_xfer_set_completed(xfer, TRUE); + return r; } diff -r a92f4cb593a4 -r 974722699032 libpurple/media-gst.h --- a/libpurple/media-gst.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/media-gst.h Mon Apr 25 20:13:05 2011 +0000 @@ -159,6 +159,31 @@ PurpleMediaElementInfo *purple_media_manager_get_active_element( PurpleMediaManager *manager, PurpleMediaElementType type); +/** + * Reduces media formats supported by the video source to given set. + * + * Useful to force negotiation of smaller picture resolution more suitable for + * use with particular codec and communication protocol without rescaling. + * + * @param manager The media manager to set the media formats. + * @param caps Set of allowed media formats. + * + * @since 2.8.0 + */ +void purple_media_manager_set_video_caps(PurpleMediaManager *manager, + GstCaps *caps); + +/** + * Returns current set of media formats limiting the output from video source. + * + * @param manager The media manager to get the media formats from. + * + * @return @c GstCaps limiting the video source's formats. + * + * @since 2.8.0 + */ +GstCaps *purple_media_manager_get_video_caps(PurpleMediaManager *manager); + gchar *purple_media_element_info_get_id(PurpleMediaElementInfo *info); gchar *purple_media_element_info_get_name(PurpleMediaElementInfo *info); PurpleMediaElementType purple_media_element_info_get_element_type( diff -r a92f4cb593a4 -r 974722699032 libpurple/media.c --- a/libpurple/media.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/media.c Mon Apr 25 20:13:05 2011 +0000 @@ -1151,12 +1151,6 @@ #endif } -#if 0 -/* - * These two functions aren't being used and I'd rather not lock in the API - * until they are needed. If they ever are. - */ - GList * purple_media_get_active_local_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *participant) @@ -1186,7 +1180,6 @@ return NULL; #endif } -#endif gboolean purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id, diff -r a92f4cb593a4 -r 974722699032 libpurple/media.h --- a/libpurple/media.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/media.h Mon Apr 25 20:13:05 2011 +0000 @@ -230,12 +230,6 @@ const gchar *sess_id, const gchar *participant); -#if 0 -/* - * These two functions aren't being used and I'd rather not lock in the API - * until they are needed. If they ever are. - */ - /** * Gets the active local candidates for the stream. * @@ -245,6 +239,8 @@ * from. * * @return The active candidates retrieved. + * + * @since 2.8.0 */ GList *purple_media_get_active_local_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *participant); @@ -258,10 +254,11 @@ * from. * * @return The remote candidates retrieved. + * + * @since 2.8.0 */ GList *purple_media_get_active_remote_candidates(PurpleMedia *media, const gchar *sess_id, const gchar *participant); -#endif /** * Sets remote candidates from the stream. diff -r a92f4cb593a4 -r 974722699032 libpurple/media/backend-fs2.c --- a/libpurple/media/backend-fs2.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/media/backend-fs2.c Mon Apr 25 20:13:05 2011 +0000 @@ -125,6 +125,7 @@ GstElement *src; GstElement *tee; + GstElement *srcvalve; GstPad *srcpad; @@ -142,6 +143,8 @@ GHashTable *participants; GList *streams; + + gdouble silence_threshold; }; enum { @@ -152,8 +155,7 @@ static void purple_media_backend_fs2_init(PurpleMediaBackendFs2 *self) -{ -} +{} static gboolean event_probe_cb(GstPad *srcpad, GstEvent *event, gboolean release_pad) @@ -766,6 +768,22 @@ return NULL; } +static gdouble +gst_msg_db_to_percent(GstMessage *msg, gchar *value_name) +{ + const GValue *list; + const GValue *value; + gdouble value_db; + gdouble percent; + + list = gst_structure_get_value( + gst_message_get_structure(msg), value_name); + value = gst_value_list_get_value(list, 0); + value_db = g_value_get_double(value); + percent = pow(10, value_db / 20); + return (percent > 1.0) ? 1.0 : percent; +} + static void gst_handle_message_element(GstBus *bus, GstMessage *msg, PurpleMediaBackendFs2 *self) @@ -778,17 +796,12 @@ if (level_id == 0) level_id = g_signal_lookup("level", PURPLE_TYPE_MEDIA); - if (g_signal_has_handler_pending(priv->media, level_id, 0, FALSE) - && gst_structure_has_name( - gst_message_get_structure(msg), "level")) { + if (gst_structure_has_name(msg->structure, "level")) { GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg)); gchar *name; gchar *participant = NULL; PurpleMediaBackendFs2Session *session = NULL; - gdouble rms_db; gdouble percent; - const GValue *list; - const GValue *value; if (!PURPLE_IS_MEDIA(priv->media) || GST_ELEMENT_PARENT(src) != priv->confbin) @@ -798,7 +811,19 @@ if (!strncmp(name, "sendlevel_", 10)) { session = get_session(self, name+10); - } else { + if (priv->silence_threshold > 0) { + percent = gst_msg_db_to_percent(msg, "decay"); + g_object_set(session->srcvalve, + "drop", (percent < priv->silence_threshold), NULL); + } + } + + g_free(name); + + if (!g_signal_has_handler_pending(priv->media, level_id, 0, FALSE)) + return; + + if (!session) { GList *iter = priv->streams; PurpleMediaBackendFs2Stream *stream; for (; iter; iter = g_list_next(iter)) { @@ -811,19 +836,10 @@ } } - g_free(name); - if (!session) return; - list = gst_structure_get_value( - gst_message_get_structure(msg), "rms"); - value = gst_value_list_get_value(list, 0); - rms_db = g_value_get_double(value); - percent = pow(10, rms_db / 20) * 5; - - if(percent > 1.0) - percent = 1.0; + percent = gst_msg_db_to_percent(msg, "rms"); g_signal_emit(priv->media, level_id, 0, session->id, participant, percent); @@ -1235,6 +1251,13 @@ return FALSE; } + if (purple_account_get_silence_suppression( + purple_media_get_account(priv->media))) + priv->silence_threshold = purple_prefs_get_int( + "/purple/media/audio/silence_threshold") / 100.0; + else + priv->silence_threshold = 0; + pipeline = purple_media_manager_get_pipeline( purple_media_get_manager(priv->media)); @@ -1376,13 +1399,17 @@ name = g_strdup_printf("sendlevel_%s", session->id); level = gst_element_factory_make("level", name); g_free(name); + session->srcvalve = gst_element_factory_make("valve", NULL); gst_bin_add(GST_BIN(priv->confbin), volume); gst_bin_add(GST_BIN(priv->confbin), level); + gst_bin_add(GST_BIN(priv->confbin), session->srcvalve); gst_element_set_state(level, GST_STATE_PLAYING); gst_element_set_state(volume, GST_STATE_PLAYING); + gst_element_set_state(session->srcvalve, GST_STATE_PLAYING); + gst_element_link(level, session->srcvalve); gst_element_link(volume, level); gst_element_link(session->tee, volume); - srcpad = gst_element_get_static_pad(level, "src"); + srcpad = gst_element_get_static_pad(session->srcvalve, "src"); g_object_set(volume, "volume", input_volume, NULL); } else { srcpad = gst_element_get_request_pad(session->tee, "src%d"); diff -r a92f4cb593a4 -r 974722699032 libpurple/mediamanager.c --- a/libpurple/mediamanager.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/mediamanager.c Mon Apr 25 20:13:05 2011 +0000 @@ -175,6 +175,7 @@ purple_prefs_add_none("/purple/media"); purple_prefs_add_none("/purple/media/audio"); + purple_prefs_add_int("/purple/media/audio/silence_threshold", 5); purple_prefs_add_none("/purple/media/audio/volume"); purple_prefs_add_int("/purple/media/audio/volume/input", 10); purple_prefs_add_int("/purple/media/audio/volume/output", 10); @@ -419,7 +420,30 @@ #ifdef USE_GSTREAMER -static GstCaps * +void +purple_media_manager_set_video_caps(PurpleMediaManager *manager, GstCaps *caps) +{ +#ifdef USE_VV + if (manager->priv->video_caps) + gst_caps_unref(manager->priv->video_caps); + + manager->priv->video_caps = caps; + + if (manager->priv->pipeline && manager->priv->video_src) { + gchar *id = purple_media_element_info_get_id(manager->priv->video_src); + GstElement *src = gst_bin_get_by_name(GST_BIN(manager->priv->pipeline), id); + + if (src) { + GstElement *capsfilter = gst_bin_get_by_name(GST_BIN(src), "prpl_video_caps"); + g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL); + } + + g_free(id); + } +#endif +} + +GstCaps * purple_media_manager_get_video_caps(PurpleMediaManager *manager) { #ifdef USE_VV diff -r a92f4cb593a4 -r 974722699032 libpurple/notify.c --- a/libpurple/notify.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/notify.c Mon Apr 25 20:13:05 2011 +0000 @@ -602,6 +602,18 @@ } void +purple_notify_user_info_add_pair_plaintext(PurpleNotifyUserInfo *user_info, const char *label, const char *value) +{ + gchar *escaped; + PurpleNotifyUserInfoEntry *entry; + + escaped = g_markup_escape_text(value, -1); + entry = purple_notify_user_info_entry_new(label, escaped); + g_free(escaped); + user_info->user_info_entries = g_list_append(user_info->user_info_entries, entry); +} + +void purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value) { PurpleNotifyUserInfoEntry *entry; diff -r a92f4cb593a4 -r 974722699032 libpurple/notify.h --- a/libpurple/notify.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/notify.h Mon Apr 25 20:13:05 2011 +0000 @@ -540,13 +540,28 @@ * a colon. If NULL, value will be displayed without a * label. * @param value The value, which might be displayed by a UI after - * the label. If NULL, label will still be displayed; - * the UI should then treat label as independent and not + * the label. This should be valid HTML. If you want + * to insert plaintext then use + * purple_notify_user_info_add_pair_plaintext(), instead. + * If this is NULL the label will still be displayed; + * the UI should treat label as independent and not * include a colon if it would otherwise. */ +/* + * TODO: In 3.0.0 this function should be renamed to + * purple_notify_user_info_add_pair_html(). And optionally + * purple_notify_user_info_add_pair_plaintext() could be renamed to + * purple_notify_user_info_add_pair(). + */ void purple_notify_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value); /** + * Like purple_notify_user_info_add_pair, but value should be plaintext + * and will be escaped using g_markup_escape_text(). + */ +void purple_notify_user_info_add_pair_plaintext(PurpleNotifyUserInfo *user_info, const char *label, const char *value); + +/** * Prepend a label/value pair to a PurpleNotifyUserInfo object * * @param user_info The PurpleNotifyUserInfo diff -r a92f4cb593a4 -r 974722699032 libpurple/plugins/fortuneprofile.pl --- a/libpurple/plugins/fortuneprofile.pl Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/plugins/fortuneprofile.pl Mon Apr 25 20:13:05 2011 +0000 @@ -51,7 +51,7 @@ summary => "Sets your AIM profile to a fortune (with a header and footer of your choice).", description => "Sets your AIM profile to a fortune (with a header and footer of your choice).", author => "Sean Egan ", - url => "http://gaim.sf.net/", + url => "http://pidgin.im/", load => "plugin_load" ); diff -r a92f4cb593a4 -r 974722699032 libpurple/plugins/perl/common/Conversation.xs --- a/libpurple/plugins/perl/common/Conversation.xs Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/plugins/perl/common/Conversation.xs Mon Apr 25 20:13:05 2011 +0000 @@ -118,6 +118,12 @@ XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::Conversation"))); } +Purple::Conversation +purple_find_conversation_with_account(type, name, account) + Purple::ConversationType type + const char *name + Purple::Account account + MODULE = Purple::Conversation PACKAGE = Purple::Conversations PREFIX = purple_conversations_ PROTOTYPES: ENABLE @@ -297,6 +303,12 @@ const char *message void +purple_conv_im_send_with_flags(im, message, flags) + Purple::Conversation::IM im + const char *message + Purple::MessageFlags flags + +void purple_conv_im_write(im, who, message, flags, mtime) Purple::Conversation::IM im const char *who @@ -410,6 +422,12 @@ const char * message void +purple_conv_chat_send_with_flags(chat, message, flags) + Purple::Conversation::Chat chat + const char * message + Purple::MessageFlags flags + +void purple_conv_chat_write(chat, who, message, flags, mtime) Purple::Conversation::Chat chat const char *who diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/bonjour/bonjour.c --- a/libpurple/protocols/bonjour/bonjour.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Mon Apr 25 20:13:05 2011 +0000 @@ -534,7 +534,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/gg/gg.c --- a/libpurple/protocols/gg/gg.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/gg/gg.c Mon Apr 25 20:13:05 2011 +0000 @@ -49,6 +49,10 @@ static PurplePlugin *my_protocol = NULL; +/* Prototypes */ +static void ggp_set_status(PurpleAccount *account, PurpleStatus *status); +static int ggp_to_gg_status(PurpleStatus *status, char **msg); + /* ---------------------------------------------------------------------- */ /* ----- EXTERNAL CALLBACKS --------------------------------------------- */ /* ---------------------------------------------------------------------- */ @@ -755,6 +759,61 @@ ggp_token_request(gc, ggp_change_passwd_dialog); } +/* ----- CHANGE STATUS BROADCASTING ------------------------------------------------ */ + +static void ggp_action_change_status_broadcasting_ok(PurpleConnection *gc, PurpleRequestFields *fields) +{ + GGPInfo *info = gc->proto_data; + int selected_field; + PurpleAccount *account = purple_connection_get_account(gc); + PurpleStatus *status; + + selected_field = purple_request_fields_get_choice(fields, "status_broadcasting"); + + if (selected_field == 0) + info->status_broadcasting = TRUE; + else + info->status_broadcasting = FALSE; + + status = purple_account_get_active_status(account); + + ggp_set_status(account, status); +} + +static void ggp_action_change_status_broadcasting(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *)action->context; + GGPInfo *info = gc->proto_data; + + PurpleRequestFields *fields; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + + fields = purple_request_fields_new(); + group = purple_request_field_group_new(NULL); + purple_request_fields_add_group(fields, group); + + field = purple_request_field_choice_new("status_broadcasting", _("Show status to:"), 0); + purple_request_field_choice_add(field, _("All people")); + purple_request_field_choice_add(field, _("Only buddies")); + purple_request_field_group_add_field(group, field); + + if (info->status_broadcasting) + purple_request_field_choice_set_default_value(field, 0); + else + purple_request_field_choice_set_default_value(field, 1); + + purple_request_fields(gc, + _("Change status broadcasting"), + _("Change status broadcasting"), + _("Please, select who can see your status"), + fields, + _("OK"), G_CALLBACK(ggp_action_change_status_broadcasting_ok), + _("Cancel"), NULL, + purple_connection_get_account(gc), NULL, NULL, + gc); +} + /* ----- CONFERENCES ---------------------------------------------------- */ static void ggp_callback_add_to_chat_ok(PurpleBuddy *buddy, PurpleRequestFields *fields) @@ -856,10 +915,6 @@ /* ----- INTERNAL CALLBACKS --------------------------------------------- */ /* ---------------------------------------------------------------------- */ -/* Prototypes */ -static void ggp_set_status(PurpleAccount *account, PurpleStatus *status); -static int ggp_to_gg_status(PurpleStatus *status, char **msg); - struct gg_fetch_avatar_data { PurpleConnection *gc; @@ -1948,7 +2003,8 @@ info->searches = ggp_search_new(); info->pending_richtext_messages = NULL; info->pending_images = g_hash_table_new(g_int_hash, g_int_equal); - + info->status_broadcasting = purple_account_get_bool(account, "status_broadcasting", TRUE); + gc->proto_data = info; glp->uin = ggp_get_uin(account); @@ -1965,6 +2021,9 @@ glp->status = ggp_to_gg_status(status, &glp->status_descr); glp->tls = 0; + if (!info->status_broadcasting) + glp->status = glp->status|GG_STATUS_FRIENDS_MASK; + address = purple_account_get_string(account, "gg_server", ""); if (address && *address) { /* TODO: Make this non-blocking */ @@ -2021,6 +2080,8 @@ gg_free_session(info->session); } + purple_account_set_bool(account, "status_broadcasting", info->status_broadcasting); + /* Immediately close any notifications on this handle since that process depends * upon the contents of info->searches, which we are about to destroy. */ @@ -2243,6 +2304,9 @@ new_status = ggp_to_gg_status(status, &new_msg); + if (!info->status_broadcasting) + new_status = new_status|GG_STATUS_FRIENDS_MASK; + if (new_msg == NULL) { gg_change_status(info->session, new_status); } else { @@ -2431,6 +2495,10 @@ ggp_action_buddylist_load); m = g_list_append(m, act); + act = purple_plugin_action_new(_("Change status broadcasting"), + ggp_action_change_status_broadcasting); + m = g_list_append(m, act); + return m; } @@ -2512,7 +2580,9 @@ NULL, /* can_do_media */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = { diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/gg/gg.h --- a/libpurple/protocols/gg/gg.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/gg/gg.h Mon Apr 25 20:13:05 2011 +0000 @@ -64,6 +64,7 @@ int chats_count; GList *pending_richtext_messages; GHashTable *pending_images; + gboolean status_broadcasting; //When TRUE status is visible to all, when FALSE status is visible only to friends. } GGPInfo; #endif /* _PURPLE_GG_H */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/gg/lib/libgadu.h --- a/libpurple/protocols/gg/lib/libgadu.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/gg/lib/libgadu.h Mon Apr 25 20:13:05 2011 +0000 @@ -33,10 +33,11 @@ #ifndef __GG_LIBGADU_H #define __GG_LIBGADU_H -#ifdef __cplusplus #ifdef _WIN32 #pragma pack(push, 1) #endif + +#ifdef __cplusplus extern "C" { #endif @@ -117,7 +118,7 @@ typedef unsigned short uint16_t; typedef unsigned int uint32_t; -#if !defined(__CYGWIN__) && !defined(__SunOS) +#if !defined(__CYGWIN__) && !defined(__SunOS) && !defined(_INCLUDE_HPUX_SOURCE) #define __int8_t_defined typedef signed char int8_t; typedef signed short int16_t; @@ -2056,10 +2057,11 @@ #ifdef __cplusplus } +#endif + #ifdef _WIN32 #pragma pack(pop) #endif -#endif #endif /* __GG_LIBGADU_H */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/irc/irc.c --- a/libpurple/protocols/irc/irc.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/irc/irc.c Mon Apr 25 20:13:05 2011 +0000 @@ -41,6 +41,8 @@ static void irc_ison_buddy_init(char *name, struct irc_buddy *ib, GList **list); +static void irc_who_channel(PurpleConversation *conv, struct irc_conn *irc); + static const char *irc_blist_icon(PurpleAccount *a, PurpleBuddy *b); static GList *irc_status_types(PurpleAccount *account); static GList *irc_actions(PurplePlugin *plugin, gpointer context); @@ -232,6 +234,26 @@ *list = g_list_append(*list, ib); } + +gboolean irc_who_channel_timeout(struct irc_conn *irc) +{ + // WHO all of our channels. + g_list_foreach(purple_get_conversations(), (GFunc)irc_who_channel, (gpointer)irc); + + return TRUE; +} + +static void irc_who_channel(PurpleConversation *conv, struct irc_conn *irc) +{ + if (purple_conversation_get_account(conv) == irc->account && purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { + char *buf = irc_format(irc, "vc", "WHO", purple_conversation_get_name(conv)); + + purple_debug(PURPLE_DEBUG_INFO, "irc", "Performing periodic who on %s", purple_conversation_get_name(conv)); + irc_send(irc, buf); + g_free(buf); + } +} + static void irc_ison_one(struct irc_conn *irc, struct irc_buddy *ib) { char *buf; @@ -517,6 +539,8 @@ } if (irc->timer) purple_timeout_remove(irc->timer); + if (irc->who_channel_timer) + purple_timeout_remove(irc->who_channel_timer); g_hash_table_destroy(irc->cmds); g_hash_table_destroy(irc->msgs); g_hash_table_destroy(irc->buddies); @@ -966,7 +990,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static gboolean load_plugin (PurplePlugin *plugin) { diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/irc/irc.h --- a/libpurple/protocols/irc/irc.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/irc/irc.h Mon Apr 25 20:13:05 2011 +0000 @@ -55,6 +55,7 @@ char *server; int fd; guint timer; + guint who_channel_timer; GHashTable *buddies; gboolean ison_outstanding; @@ -106,6 +107,7 @@ int irc_send(struct irc_conn *irc, const char *buf); gboolean irc_blist_timeout(struct irc_conn *irc); +gboolean irc_who_channel_timeout(struct irc_conn *irc); void irc_buddy_query(struct irc_conn *irc); char *irc_escape_privmsg(const char *text, gssize length); @@ -164,6 +166,7 @@ void irc_msg_unknown(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_wallops(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_whois(struct irc_conn *irc, const char *name, const char *from, char **args); +void irc_msg_who(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_ignore(struct irc_conn *irc, const char *name, const char *from, char **args); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/irc/msgs.c --- a/libpurple/protocols/irc/msgs.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/irc/msgs.c Mon Apr 25 20:13:05 2011 +0000 @@ -110,6 +110,8 @@ irc_blist_timeout(irc); if (!irc->timer) irc->timer = purple_timeout_add_seconds(45, (GSourceFunc)irc_blist_timeout, (gpointer)irc); + if (!irc->who_channel_timer) + irc->who_channel_timer = purple_timeout_add_seconds(300, (GSourceFunc)irc_who_channel_timeout, (gpointer)irc); } void irc_msg_default(struct irc_conn *irc, const char *name, const char *from, char **args) @@ -400,6 +402,59 @@ memset(&irc->whois, 0, sizeof(irc->whois)); } +void irc_msg_who(struct irc_conn *irc, const char *name, const char *from, char **args) +{ + if (!strcmp(name, "352")) { + PurpleConversation *conv; + PurpleConvChat *chat; + PurpleConvChatBuddy *cb; + + char *userhost, *realname; + + PurpleConvChatBuddyFlags flags; + GList *keys = NULL, *values = NULL; + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); + if (!conv) { + purple_debug(PURPLE_DEBUG_ERROR, "irc", "Got a WHO response for %s, which doesn't exist\n", args[1]); + return; + } + + cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), args[5]); + if (!cb) { + purple_debug(PURPLE_DEBUG_ERROR, "irc", "Got a WHO response for %s who isn't a buddy.\n", args[5]); + return; + } + + chat = PURPLE_CONV_CHAT(conv); + + userhost = g_strdup_printf("%s@%s", args[2], args[3]); + realname = g_strdup(args[8]); + + keys = g_list_prepend(keys, "userhost"); + values = g_list_prepend(values, userhost); + + keys = g_list_prepend(keys, "realname"); + values = g_list_prepend(values, realname); + + purple_conv_chat_cb_set_attributes(chat, cb, keys, values); + + g_list_free(keys); + g_list_free(values); + + g_free(userhost); + g_free(realname); + + flags = purple_conv_chat_user_get_flags(chat, cb->name); + + if (args[6][0] == 'G' && !(flags & PURPLE_CBFLAGS_AWAY)) { + purple_conv_chat_user_set_flags(chat, cb->name, flags | PURPLE_CBFLAGS_AWAY); + } else if(args[6][0] == 'H' && (flags & PURPLE_CBFLAGS_AWAY)) { + purple_conv_chat_user_set_flags(chat, cb->name, flags & ~PURPLE_CBFLAGS_AWAY); + } + } +} + void irc_msg_list(struct irc_conn *irc, const char *name, const char *from, char **args) { if (!irc->roomlist) @@ -797,7 +852,10 @@ { PurpleConnection *gc = purple_account_get_connection(irc->account); PurpleConversation *convo; - char *nick = irc_mask_nick(from), *userhost; + PurpleConvChat *chat; + PurpleConvChatBuddy *cb; + + char *nick = irc_mask_nick(from), *userhost, *buf; struct irc_buddy *ib; static int id = 1; @@ -820,6 +878,12 @@ } purple_conversation_set_data(convo, IRC_NAMES_FLAG, GINT_TO_POINTER(FALSE)); + + // Get the real name and user host for all participants. + buf = irc_format(irc, "vc", "WHO", args[0]); + irc_send(irc, buf); + g_free(buf); + /* Until purple_conversation_present does something that * one would expect in Pidgin, this call produces buggy * behavior both for the /join and auto-join cases. */ @@ -835,8 +899,16 @@ } userhost = irc_mask_userhost(from); - purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), nick, userhost, PURPLE_CBFLAGS_NONE, TRUE); - + chat = PURPLE_CONV_CHAT(convo); + + purple_conv_chat_add_user(chat, nick, userhost, PURPLE_CBFLAGS_NONE, TRUE); + + cb = purple_conv_chat_cb_find(chat, nick); + + if (cb) { + purple_conv_chat_cb_set_attribute(chat, cb, "userhost", userhost); + } + if ((ib = g_hash_table_lookup(irc->buddies, nick)) != NULL) { ib->new_online_status = TRUE; irc_buddy_status(nick, ib, irc); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/irc/parse.c --- a/libpurple/protocols/irc/parse.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/irc/parse.c Mon Apr 25 20:13:05 2011 +0000 @@ -65,6 +65,7 @@ { "319", "nn:", irc_msg_whois }, /* Whois channels */ { "320", "nn:", irc_msg_whois }, /* Whois (fn ident) */ { "314", "nnnvv:", irc_msg_whois }, /* Whowas user */ + { "315", "nt:", irc_msg_who }, /* end of WHO channel */ { "369", "nt:", irc_msg_endwhois }, /* End of WHOWAS */ { "321", "*", irc_msg_list }, /* Start of list */ { "322", "ncv:", irc_msg_list }, /* List. */ @@ -73,6 +74,7 @@ { "331", "nc:", irc_msg_topic }, /* No channel topic */ { "332", "nc:", irc_msg_topic }, /* Channel topic */ { "333", "*", irc_msg_ignore }, /* Topic setter stuff */ + { "352", "nvcvnvvv:", irc_msg_who },/* Channel WHO */ { "353", "nvc:", irc_msg_names }, /* Names list */ { "366", "nc:", irc_msg_names }, /* End of names */ { "367", "ncnnv", irc_msg_ban }, /* Ban list */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/auth_scram.c --- a/libpurple/protocols/jabber/auth_scram.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/auth_scram.c Mon Apr 25 20:13:05 2011 +0000 @@ -375,7 +375,7 @@ gchar *tmp, *tmp2; tmp = purple_strreplace(in, "=", "=3D"); - tmp2 = purple_strreplace(tmp, ",", "=2D"); + tmp2 = purple_strreplace(tmp, ",", "=2C"); g_free(tmp); return tmp2; } diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/bosh.c --- a/libpurple/protocols/jabber/bosh.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/bosh.c Mon Apr 25 20:13:05 2011 +0000 @@ -484,7 +484,13 @@ /* Shouldn't happen; this should be the only place pipelining * is turned off. */ +#if GLIB_CHECK_VERSION(2,16,0) g_warn_if_reached(); +#else + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "(%s:%d):%s%s code should not be reached", + __FILE__, __LINE__, G_STRFUNC, G_STRFUNC[0] ? ":" : ""); +#endif } } diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/buddy.c Mon Apr 25 20:13:05 2011 +0000 @@ -1021,7 +1021,7 @@ if (!serverside_alias) serverside_alias = g_strdup(text); - purple_notify_user_info_add_pair(user_info, _("Full Name"), text); + purple_notify_user_info_add_pair_plaintext(user_info, _("Full Name"), text); } else if(!strcmp(child->name, "N")) { for(child2 = child->child; child2; child2 = child2->next) { @@ -1032,11 +1032,11 @@ text2 = xmlnode_get_data(child2); if(text2 && !strcmp(child2->name, "FAMILY")) { - purple_notify_user_info_add_pair(user_info, _("Family Name"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Family Name"), text2); } else if(text2 && !strcmp(child2->name, "GIVEN")) { - purple_notify_user_info_add_pair(user_info, _("Given Name"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Given Name"), text2); } else if(text2 && !strcmp(child2->name, "MIDDLE")) { - purple_notify_user_info_add_pair(user_info, _("Middle Name"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Middle Name"), text2); } g_free(text2); } @@ -1047,10 +1047,10 @@ g_free(serverside_alias); serverside_alias = g_strdup(text); - purple_notify_user_info_add_pair(user_info, _("Nickname"), text); + purple_notify_user_info_add_pair_plaintext(user_info, _("Nickname"), text); } } else if(text && !strcmp(child->name, "BDAY")) { - purple_notify_user_info_add_pair(user_info, _("Birthday"), text); + purple_notify_user_info_add_pair_plaintext(user_info, _("Birthday"), text); } else if(!strcmp(child->name, "ADR")) { gboolean address_line_added = FALSE; @@ -1074,25 +1074,25 @@ } if(!strcmp(child2->name, "POBOX")) { - purple_notify_user_info_add_pair(user_info, _("P.O. Box"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("P.O. Box"), text2); } else if (g_str_equal(child2->name, "EXTADD") || g_str_equal(child2->name, "EXTADR")) { /* * EXTADD is correct, EXTADR is generated by other * clients. The next time someone reads this, remove * EXTADR. */ - purple_notify_user_info_add_pair(user_info, _("Extended Address"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Extended Address"), text2); } else if(!strcmp(child2->name, "STREET")) { - purple_notify_user_info_add_pair(user_info, _("Street Address"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Street Address"), text2); } else if(!strcmp(child2->name, "LOCALITY")) { - purple_notify_user_info_add_pair(user_info, _("Locality"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Locality"), text2); } else if(!strcmp(child2->name, "REGION")) { - purple_notify_user_info_add_pair(user_info, _("Region"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Region"), text2); } else if(!strcmp(child2->name, "PCODE")) { - purple_notify_user_info_add_pair(user_info, _("Postal Code"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Postal Code"), text2); } else if(!strcmp(child2->name, "CTRY") || !strcmp(child2->name, "COUNTRY")) { - purple_notify_user_info_add_pair(user_info, _("Country"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Country"), text2); } g_free(text2); } @@ -1106,13 +1106,13 @@ /* show what kind of number it is */ number = xmlnode_get_data(child2); if(number) { - purple_notify_user_info_add_pair(user_info, _("Telephone"), number); + purple_notify_user_info_add_pair_plaintext(user_info, _("Telephone"), number); g_free(number); } } else if((number = xmlnode_get_data(child))) { /* lots of clients (including purple) do this, but it's * out of spec */ - purple_notify_user_info_add_pair(user_info, _("Telephone"), number); + purple_notify_user_info_add_pair_plaintext(user_info, _("Telephone"), number); g_free(number); } } else if(!strcmp(child->name, "EMAIL")) { @@ -1153,18 +1153,18 @@ text2 = xmlnode_get_data(child2); if(text2 && !strcmp(child2->name, "ORGNAME")) { - purple_notify_user_info_add_pair(user_info, _("Organization Name"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Organization Name"), text2); } else if(text2 && !strcmp(child2->name, "ORGUNIT")) { - purple_notify_user_info_add_pair(user_info, _("Organization Unit"), text2); + purple_notify_user_info_add_pair_plaintext(user_info, _("Organization Unit"), text2); } g_free(text2); } } else if(text && !strcmp(child->name, "TITLE")) { - purple_notify_user_info_add_pair(user_info, _("Job Title"), text); + purple_notify_user_info_add_pair_plaintext(user_info, _("Job Title"), text); } else if(text && !strcmp(child->name, "ROLE")) { - purple_notify_user_info_add_pair(user_info, _("Role"), text); + purple_notify_user_info_add_pair_plaintext(user_info, _("Role"), text); } else if(text && !strcmp(child->name, "DESC")) { - purple_notify_user_info_add_pair(user_info, _("Description"), text); + purple_notify_user_info_add_pair_plaintext(user_info, _("Description"), text); } else if(!strcmp(child->name, "PHOTO") || !strcmp(child->name, "LOGO")) { char *bintext = NULL; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/chat.c --- a/libpurple/protocols/jabber/chat.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/chat.c Mon Apr 25 20:13:05 2011 +0000 @@ -237,6 +237,7 @@ chat = g_new0(JabberChat, 1); chat->js = js; + chat->joined = 0; chat->room = g_strdup(room); chat->server = g_strdup(server); @@ -280,6 +281,14 @@ char *jid; + char *history_maxchars; + char *history_maxstanzas; + char *history_seconds; + char *history_since; + + struct tm history_since_datetime; + const char *history_since_string = NULL; + chat = jabber_chat_new(js, room, server, handle, password, data); if (chat == NULL) return NULL; @@ -296,6 +305,22 @@ xmlnode_set_attrib(presence, "to", jid); g_free(jid); + history_maxchars = g_hash_table_lookup(data, "history_maxchars"); + history_maxstanzas = g_hash_table_lookup(data, "history_maxstanzas"); + history_seconds = g_hash_table_lookup(data, "history_seconds"); + history_since = g_hash_table_lookup(data, "history_since"); + + if (history_since) { + if (purple_str_to_time(history_since, TRUE, &history_since_datetime, NULL, NULL) != 0) { + history_since_string = purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", &history_since_datetime); + } else { + history_since_string = NULL; + + purple_debug_error("jabber", "Invalid date format for history_since" + " while requesting history: %s", history_since); + } + } + x = xmlnode_new_child(presence, "x"); xmlnode_set_namespace(x, "http://jabber.org/protocol/muc"); @@ -304,6 +329,27 @@ xmlnode_insert_data(p, password, -1); } + if ((history_maxchars && *history_maxchars) + || (history_maxstanzas && *history_maxstanzas) + || (history_seconds && *history_seconds) + || (history_since_string && *history_since_string)) { + + xmlnode *history = xmlnode_new_child(x, "history"); + + if (history_maxchars && *history_maxchars) { + xmlnode_set_attrib(history, "maxchars", history_maxchars); + } + if (history_maxstanzas && *history_maxstanzas) { + xmlnode_set_attrib(history, "maxstanzas", history_maxstanzas); + } + if (history_seconds && *history_seconds) { + xmlnode_set_attrib(history, "seconds", history_seconds); + } + if (history_since_string && *history_since_string) { + xmlnode_set_attrib(history, "since", history_since_string); + } + } + jabber_send(js, presence); xmlnode_free(presence); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/chat.h --- a/libpurple/protocols/jabber/chat.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/chat.h Mon Apr 25 20:13:05 2011 +0000 @@ -52,6 +52,7 @@ void *config_dialog_handle; GHashTable *members; gboolean left; + time_t joined; } JabberChat; GList *jabber_chat_info(PurpleConnection *gc); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/jabber.c Mon Apr 25 20:13:05 2011 +0000 @@ -2619,6 +2619,7 @@ if(!(server = g_hash_table_lookup(components, "server"))) continue; + /* FIXME: Collate is wrong in a few cases here; this should be prepped */ if(jid->node && jid->domain && !g_utf8_collate(room, jid->node) && !g_utf8_collate(server, jid->domain)) { jabber_id_free(jid); @@ -3007,21 +3008,44 @@ { JabberChat *chat = jabber_chat_find_by_conv(conv); GHashTable *components; - - if(!chat || !args || !args[0]) + JabberID *jid; + const char *room = NULL, *server = NULL, *handle = NULL; + + if (!chat || !args || !args[0]) return PURPLE_CMD_RET_FAILED; components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); - g_hash_table_replace(components, "room", args[0]); - g_hash_table_replace(components, "server", chat->server); - g_hash_table_replace(components, "handle", chat->handle); - if(args[1]) - g_hash_table_replace(components, "password", args[1]); + jid = jabber_id_new(args[0]); + if (jid) { + room = jid->node; + server = jid->domain; + handle = jid->resource ? jid->resource : chat->handle; + } else { + /* If jabber_id_new failed, the user may have just passed in + * a room name. For backward compatibility, handle that here. + */ + if (strchr(args[0], '@')) { + *error = g_strdup(_("Invalid XMPP ID")); + return PURPLE_CMD_RET_FAILED; + } + + room = args[0]; + server = chat->server; + handle = chat->handle; + } + + g_hash_table_insert(components, "room", (gpointer)room); + g_hash_table_insert(components, "server", (gpointer)server); + g_hash_table_insert(components, "handle", (gpointer)handle); + + if (args[1]) + g_hash_table_insert(components, "password", args[1]); jabber_chat_join(purple_conversation_get_gc(conv), components); g_hash_table_destroy(components); + jabber_id_free(jid); return PURPLE_CMD_RET_OK; } @@ -3649,6 +3673,7 @@ PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", jabber_cmd_chat_join, _("join: <room> [password]: Join a chat on this server."), + /* _("join: <room[@server]> [password]: Join a chat."), */ NULL); commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/jutil.c --- a/libpurple/protocols/jabber/jutil.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/jutil.c Mon Apr 25 20:13:05 2011 +0000 @@ -501,12 +501,9 @@ jabber_id_free(JabberID *jid) { if(jid) { - if(jid->node) - g_free(jid->node); - if(jid->domain) - g_free(jid->domain); - if(jid->resource) - g_free(jid->resource); + g_free(jid->node); + g_free(jid->domain); + g_free(jid->resource); g_free(jid); } } diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/libxmpp.c --- a/libpurple/protocols/jabber/libxmpp.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Mon Apr 25 20:13:05 2011 +0000 @@ -129,7 +129,9 @@ jabber_get_media_caps, /* get_media_caps */ jabber_get_moods, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static gboolean load_plugin(PurplePlugin *plugin) diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/message.c --- a/libpurple/protocols/jabber/message.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/message.c Mon Apr 25 20:13:05 2011 +0000 @@ -1140,6 +1140,12 @@ if(!who || !msg) return 0; + if (purple_debug_is_verbose()) { + /* TODO: Maybe we need purple_debug_is_really_verbose? :) */ + purple_debug_misc("jabber", "jabber_message_send_im: who='%s'\n" + "\tmsg='%s'\n", who, msg); + } + resource = jabber_get_resource(who); jb = jabber_buddy_find(gc->proto_data, who, TRUE); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/presence.c --- a/libpurple/protocols/jabber/presence.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/presence.c Mon Apr 25 20:13:05 2011 +0000 @@ -588,7 +588,9 @@ role = xmlnode_get_attrib(presence->chat_info.item, "role"); } - if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(110))) + if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(110)) || + g_str_equal(presence->jid_from->resource, chat->handle) || + purple_strequal(presence->to, jid)) is_our_resource = TRUE; if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(201))) { @@ -639,10 +641,14 @@ if(!jabber_chat_find_buddy(chat->conv, presence->jid_from->resource)) purple_conv_chat_add_user(PURPLE_CONV_CHAT(chat->conv), presence->jid_from->resource, - jid, flags, !presence->delayed); + jid, flags, chat->joined > 0 && ((!presence->delayed) || (presence->sent > chat->joined))); else purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(chat->conv), presence->jid_from->resource, flags); + + if (is_our_resource && chat->joined == 0) + chat->joined = time(NULL); + } else if (presence->type == JABBER_PRESENCE_UNAVAILABLE) { gboolean nick_change = FALSE; gboolean kick = FALSE; @@ -661,7 +667,7 @@ return FALSE; } - is_our_resource = (0 == g_utf8_collate(presence->jid_from->resource, chat->handle)); + is_our_resource = g_str_equal(presence->jid_from->resource, chat->handle); jabber_buddy_remove_resource(presence->jb, presence->jid_from->resource); @@ -669,8 +675,10 @@ jid = xmlnode_get_attrib(presence->chat_info.item, "jid"); if (chat->muc) { - if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(110))) + if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(110))) { is_our_resource = TRUE; + chat->joined = 0; + } if (g_slist_find(presence->chat_info.codes, GINT_TO_POINTER(301))) { /* XXX: We got banned. YAY! (No GIR, that's bad) */ @@ -691,6 +699,7 @@ if (g_str_equal(presence->jid_from->resource, chat->handle)) { /* Changing our own nickname */ g_free(chat->handle); + /* TODO: This should be resourceprep'd */ chat->handle = g_strdup(nick); } @@ -1158,9 +1167,6 @@ static void parse_delay(JabberStream *js, JabberPresence *presence, xmlnode *delay) { - /* XXX: compare the time. Can happen on presence stanzas that aren't - * actually delayed. - */ const char *stamp = xmlnode_get_attrib(delay, "stamp"); presence->delayed = TRUE; presence->sent = purple_str_to_time(stamp, TRUE, NULL, NULL, NULL); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/jabber/si.c Mon Apr 25 20:13:05 2011 +0000 @@ -1699,7 +1699,7 @@ return; if((filesize_c = xmlnode_get_attrib(file, "size"))) - filesize = atoi(filesize_c); + filesize = strtoul(filesize_c, NULL, 10); if(!(feature = xmlnode_get_child(si, "feature"))) return; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/Makefile.mingw --- a/libpurple/protocols/msn/Makefile.mingw Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/Makefile.mingw Mon Apr 25 20:13:05 2011 +0000 @@ -65,6 +65,7 @@ sbconn.c \ switchboard.c \ table.c \ + tlv.c \ transaction.c \ user.c \ userlist.c \ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/contact.c --- a/libpurple/protocols/msn/contact.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/contact.c Mon Apr 25 20:13:05 2011 +0000 @@ -363,10 +363,9 @@ char *type; char *member_id; MsnUser *user; - xmlnode *annotation, *display; + xmlnode *annotation; guint nid = MSN_NETWORK_UNKNOWN; char *invite = NULL; - char *display_text; passport = xmlnode_get_data(xmlnode_get_child(member, node)); if (!msn_email_is_valid(passport)) { @@ -376,13 +375,8 @@ type = xmlnode_get_data(xmlnode_get_child(member, "Type")); member_id = xmlnode_get_data(xmlnode_get_child(member, "MembershipId")); - if ((display = xmlnode_get_child(member, "DisplayName"))) { - display_text = xmlnode_get_data(display); - } else { - display_text = NULL; - } - user = msn_userlist_find_add_user(session->userlist, passport, display_text); + user = msn_userlist_find_add_user(session->userlist, passport, NULL); for (annotation = xmlnode_get_child(member, "Annotations/Annotation"); annotation; @@ -423,7 +417,6 @@ g_free(type); g_free(member_id); g_free(invite); - g_free(display_text); } static void diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/msg.c --- a/libpurple/protocols/msn/msg.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/msg.c Mon Apr 25 20:13:05 2011 +0000 @@ -613,7 +613,8 @@ if (msg->msnslp_message) { - msn_slpmsgpart_to_string(msg->part, str); + if (msg->part) + msn_slpmsgpart_to_string(msg->part, str); if (purple_debug_is_verbose() && body != NULL) { diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/msn.c Mon Apr 25 20:13:05 2011 +0000 @@ -95,13 +95,6 @@ MsnObject *obj; } MsnEmoticon; -typedef struct -{ - PurpleConnection *pc; - PurpleBuddy *buddy; - PurpleGroup *group; -} MsnAddReqData; - static const char * msn_normalize(const PurpleAccount *account, const char *str) { @@ -110,11 +103,9 @@ g_return_val_if_fail(str != NULL, NULL); - g_snprintf(buf, sizeof(buf), "%s%s", str, - (strchr(str, '@') ? "" : "@hotmail.com")); - - tmp = g_utf8_strdown(buf, -1); - strncpy(buf, tmp, sizeof(buf)); + tmp = g_strchomp(g_utf8_strdown(str, -1)); + g_snprintf(buf, sizeof(buf), "%s%s", tmp, + (strchr(tmp, '@') ? "" : "@hotmail.com")); g_free(tmp); return buf; @@ -931,8 +922,8 @@ if (session) { MsnUser *user = msn_userlist_find_user(session->userlist, who); if (user) { - /* Include these too: MSN_CLIENT_CAP_MSNMOBILE|MSN_CLIENT_CAP_MSNDIRECT ? */ - if ((user->clientid & MSN_CLIENT_CAP_WEBMSGR) || + /* Include these too: MSN_CAP_MOBILE_ON|MSN_CAP_WEB_WATCH ? */ + if ((user->clientid & MSN_CAP_VIA_WEBIM) || user->networkid == MSN_NETWORK_YAHOO) ret = FALSE; else @@ -961,16 +952,16 @@ MsnUser *user = purple_buddy_get_protocol_data(b); if (user != NULL) { - if (user->clientid & MSN_CLIENT_CAP_BOT) + if (user->clientid & MSN_CAP_BOT) return "bot"; - if (user->clientid & MSN_CLIENT_CAP_WIN_MOBILE) + if (user->clientid & MSN_CAP_VIA_MOBILE) return "mobile"; #if 0 /* XXX: Since we don't support this, there's no point in showing it just yet */ - if (user->clientid & MSN_CLIENT_CAP_SCHANNEL) + if (user->clientid & MSN_CAP_SCHANNEL) return "secure"; #endif - if (user->clientid & MSN_CLIENT_CAP_WEBMSGR) + if (user->clientid & MSN_CAP_VIA_WEBIM) return "external"; if (user->networkid == MSN_NETWORK_YAHOO) return "yahoo"; @@ -1042,7 +1033,6 @@ const char *psm, *name; const char *mediatype = NULL; char *currentmedia = NULL; - char *tmp; psm = purple_status_get_attr_string(status, "message"); if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { @@ -1086,9 +1076,7 @@ } if (psm != NULL && *psm) { - tmp = g_markup_escape_text(psm, -1); - purple_notify_user_info_add_pair(user_info, tmp2, tmp); - g_free(tmp); + purple_notify_user_info_add_pair_plaintext(user_info, tmp2, psm); } else { purple_notify_user_info_add_pair(user_info, _("Status"), tmp2); } @@ -1096,13 +1084,11 @@ g_free(tmp2); } else { if (psm != NULL && *psm) { - tmp = g_markup_escape_text(psm, -1); if (purple_presence_is_idle(presence)) { - purple_notify_user_info_add_pair(user_info, _("Idle"), tmp); + purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), psm); } else { - purple_notify_user_info_add_pair(user_info, _("Status"), tmp); + purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), psm); } - g_free(tmp); } else { if (purple_presence_is_idle(presence)) { purple_notify_user_info_add_pair(user_info, _("Status"), @@ -1751,65 +1737,49 @@ MsnUser *user) { char *group; + MsnUserList *userlist; + MsnUser *user2; g_return_if_fail(user != NULL); + if (network == MSN_NETWORK_UNKNOWN) { + purple_debug_error("msn", "Network in FQY response was unknown. " + "Assuming %s is a passport user and adding anyway.\n", who); + network = MSN_NETWORK_PASSPORT; + } + group = msn_user_remove_pending_group(user); - if (network != MSN_NETWORK_UNKNOWN) { - MsnUserList *userlist = session->userlist; - MsnUser *user2 = msn_userlist_find_user(userlist, who); - if (user2 != NULL) { - /* User already in userlist, so just update it. */ - msn_user_unref(user); - user = user2; - } else { - msn_userlist_add_user(userlist, user); - } - - msn_user_set_network(user, network); - msn_userlist_add_buddy(userlist, who, group); - } - else - { - PurpleBuddy * buddy = purple_find_buddy(session->account, who); - gchar *buf; - buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid. Usernames must be valid email addresses."), who); - if (!purple_conv_present_error(who, session->account, buf)) - purple_notify_error(purple_account_get_connection(session->account), NULL, _("Unable to Add"), buf); - g_free(buf); - - /* Remove from local list */ - purple_blist_remove_buddy(buddy); + userlist = session->userlist; + user2 = msn_userlist_find_user(userlist, who); + if (user2 != NULL) { + /* User already in userlist, so just update it. */ + msn_user_unref(user); + user = user2; + } else { + msn_userlist_add_user(userlist, user); msn_user_unref(user); } + + msn_user_set_network(user, network); + msn_userlist_add_buddy(userlist, who, group); + g_free(group); } static void -finish_auth_request(MsnAddReqData *data, char *msg) +msn_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group, const char *message) { - PurpleConnection *pc; - PurpleBuddy *buddy; - PurpleGroup *group; PurpleAccount *account; + const char *bname, *gname; MsnSession *session; MsnUserList *userlist; - const char *who, *gname; MsnUser *user; - pc = data->pc; - buddy = data->buddy; - group = data->group; - g_free(data); - account = purple_connection_get_account(pc); - session = pc->proto_data; - userlist = session->userlist; - - who = msn_normalize(account, purple_buddy_get_name(buddy)); - gname = group ? purple_group_get_name(group) : NULL; - purple_debug_info("msn", "Add user:%s to group:%s\n", who, gname ? gname : "(null)"); + session = purple_connection_get_protocol_data(pc); + bname = purple_buddy_get_name(buddy); + if (!session->logged_in) { purple_debug_error("msn", "msn_add_buddy called before connected\n"); @@ -1819,56 +1789,20 @@ /* XXX - Would group ever be NULL here? I don't think so... * shx: Yes it should; MSN handles non-grouped buddies, and this is only - * internal. */ - user = msn_userlist_find_user(userlist, who); - if ((user != NULL) && (user->networkid != MSN_NETWORK_UNKNOWN)) { - /* We already know this buddy and their network. This function knows - what to do with users already in the list and stuff... */ - msn_user_set_invite_message(user, msg); - msn_userlist_add_buddy(userlist, who, gname); - } else { - char **tokens; - char *fqy; - /* We need to check the network for this buddy first */ - user = msn_user_new(userlist, who, NULL); - msn_user_set_invite_message(user, msg); - msn_user_set_pending_group(user, gname); - msn_user_set_network(user, MSN_NETWORK_UNKNOWN); - tokens = g_strsplit(who, "@", 2); - fqy = g_strdup_printf("", - tokens[1], - tokens[0]); - msn_notification_send_fqy(session, fqy, strlen(fqy), - (MsnFqyCb)add_pending_buddy, user); - g_free(fqy); - g_strfreev(tokens); - } -} - -static void -cancel_auth_request(MsnAddReqData *data, char *msg) -{ - /* Remove from local list */ - purple_blist_remove_buddy(data->buddy); - - g_free(data); -} - -static void -msn_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) -{ - const char *bname; - MsnAddReqData *data; - MsnSession *session; - MsnUser *user; - - bname = purple_buddy_get_name(buddy); + * internal. + * KingAnt: But PurpleBuddys must always exist inside PurpleGroups, so + * won't group always be non-NULL here? + */ + bname = msn_normalize(account, bname); + gname = group ? purple_group_get_name(group) : NULL; + purple_debug_info("msn", "Add user:%s to group:%s\n", + bname, gname ? gname : "(null)"); if (!msn_email_is_valid(bname)) { gchar *buf; buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid. Usernames must be valid email addresses."), bname); - if (!purple_conv_present_error(bname, purple_connection_get_account(gc), buf)) - purple_notify_error(gc, NULL, _("Unable to Add"), buf); + if (!purple_conv_present_error(bname, account, buf)) + purple_notify_error(pc, NULL, _("Unable to Add"), buf); g_free(buf); /* Remove from local list */ @@ -1877,22 +1811,38 @@ return; } - data = g_new0(MsnAddReqData, 1); - data->pc = gc; - data->buddy = buddy; - data->group = group; - - session = purple_connection_get_protocol_data(gc); - user = msn_userlist_find_user(session->userlist, bname); + /* Make sure name is normalized */ + purple_blist_rename_buddy(buddy, bname); + + userlist = session->userlist; + user = msn_userlist_find_user(userlist, bname); if (user && user->authorized) { - finish_auth_request(data, NULL); + message = NULL; + } + if ((user != NULL) && (user->networkid != MSN_NETWORK_UNKNOWN)) { + /* We already know this buddy and their network. This function knows + what to do with users already in the list and stuff... */ + msn_user_set_invite_message(user, message); + msn_userlist_add_buddy(userlist, bname, gname); } else { - purple_request_input(gc, NULL, _("Authorization Request Message:"), - NULL, _("Please authorize me!"), TRUE, FALSE, NULL, - _("_OK"), G_CALLBACK(finish_auth_request), - _("_Cancel"), G_CALLBACK(cancel_auth_request), - purple_connection_get_account(gc), bname, NULL, - data); + char **tokens; + char *fqy; + /* We need to check the network for this buddy first */ + user = msn_user_new(userlist, bname, NULL); + msn_user_set_invite_message(user, message); + msn_user_set_pending_group(user, gname); + msn_user_set_network(user, MSN_NETWORK_UNKNOWN); + /* Should probably re-use the msn_add_contact_xml function here */ + tokens = g_strsplit(bname, "@", 2); + fqy = g_strdup_printf("", + tokens[1], + tokens[0]); + /* TODO: I think user will leak if we disconnect before receiving + a response to this FQY request */ + msn_notification_send_fqy(session, fqy, strlen(fqy), + (MsnFqyCb)add_pending_buddy, user); + g_free(fqy); + g_strfreev(tokens); } } @@ -2305,9 +2255,7 @@ alias = purple_buddy_get_local_buddy_alias(b); if (alias && alias[0]) { - char *aliastext = g_markup_escape_text(alias, -1); - purple_notify_user_info_add_pair(user_info, _("Alias"), aliastext); - g_free(aliastext); + purple_notify_user_info_add_pair_plaintext(user_info, _("Alias"), alias); } if ((alias = purple_buddy_get_server_alias(b)) != NULL) @@ -2979,7 +2927,7 @@ static PurplePluginProtocolInfo prpl_info = { - OPT_PROTO_MAIL_CHECK, + OPT_PROTO_MAIL_CHECK|OPT_PROTO_INVITE_MESSAGE, NULL, /* user_splits */ NULL, /* protocol_options */ {"png,gif", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_SEND}, /* icon_spec */ @@ -3000,7 +2948,7 @@ msn_set_status, /* set_away */ msn_set_idle, /* set_idle */ NULL, /* change_passwd */ - msn_add_buddy, /* add_buddy */ + NULL, /* add_buddy */ NULL, /* add_buddies */ msn_rem_buddy, /* remove_buddy */ NULL, /* remove_buddies */ @@ -3050,7 +2998,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ msn_set_public_alias, /* set_public_alias */ - msn_get_public_alias /* get_public_alias */ + msn_get_public_alias, /* get_public_alias */ + msn_add_buddy, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/msn.h --- a/libpurple/protocols/msn/msn.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/msn.h Mon Apr 25 20:13:05 2011 +0000 @@ -26,34 +26,65 @@ typedef enum { - MSN_CLIENT_CAP_WIN_MOBILE = 0x0000001, - MSN_CLIENT_CAP_INK_GIF = 0x0000004, - MSN_CLIENT_CAP_INK_ISF = 0x0000008, - MSN_CLIENT_CAP_VIDEO_CHAT = 0x0000010, - MSN_CLIENT_CAP_PACKET = 0x0000020, - MSN_CLIENT_CAP_MSNMOBILE = 0x0000040, - MSN_CLIENT_CAP_MSNDIRECT = 0x0000080, - MSN_CLIENT_CAP_WEBMSGR = 0x0000200, - MSN_CLIENT_CAP_TGW = 0x0000800, - MSN_CLIENT_CAP_SPACE = 0x0001000, - MSN_CLIENT_CAP_MCE = 0x0002000, - MSN_CLIENT_CAP_DIRECTIM = 0x0004000, - MSN_CLIENT_CAP_WINKS = 0x0008000, - MSN_CLIENT_CAP_SEARCH = 0x0010000, - MSN_CLIENT_CAP_BOT = 0x0020000, - MSN_CLIENT_CAP_VOICEIM = 0x0040000, - MSN_CLIENT_CAP_SCHANNEL = 0x0080000, - MSN_CLIENT_CAP_SIP_INVITE = 0x0100000, - MSN_CLIENT_CAP_SDRIVE = 0x0400000, - MSN_CLIENT_CAP_ONECARE = 0x1000000, - MSN_CLIENT_CAP_P2P_TURN = 0x2000000, - MSN_CLIENT_CAP_P2P_BOOTSTRAP_VIA_UUN = 0x4000000, + MSN_CAP_VIA_MOBILE = 0x0000001, + MSN_CAP_VIA_TEXAS = 0x0000002, + MSN_CAP_INK_GIF = 0x0000004, + MSN_CAP_INK_ISF = 0x0000008, + MSN_CAP_VIDEO_CHAT = 0x0000010, + MSN_CAP_PACKET = 0x0000020, + MSN_CAP_MOBILE_ON = 0x0000040, + MSN_CAP_WEB_WATCH = 0x0000080, + MSN_CAP_ACTIVITIES = 0x0000100, + MSN_CAP_VIA_WEBIM = 0x0000200, + MSN_CAP_MOBILE_DEV = 0x0000400, + MSN_CAP_VIA_FEDERATED = 0x0000800, + MSN_CAP_SPACE = 0x0001000, + MSN_CAP_MCE = 0x0002000, + MSN_CAP_DIRECTIM = 0x0004000, + MSN_CAP_WINKS = 0x0008000, + MSN_CAP_SEARCH = 0x0010000, + MSN_CAP_BOT = 0x0020000, + MSN_CAP_VOICEIM = 0x0040000, + MSN_CAP_SCHANNEL = 0x0080000, + MSN_CAP_SIP_INVITE = 0x0100000, + MSN_CAP_MULTI_VV = 0x0200000, + MSN_CAP_SDRIVE = 0x0400000, + MSN_CAP_PAGEMODE_MSG = 0x080000, + MSN_CAP_ONECARE = 0x1000000, + MSN_CAP_P2P_TURN = 0x2000000, + MSN_CAP_P2P_BOOTSTRAP_VIA_UUN = 0x4000000, + MSN_CAP_ALIASED = 0x8000000 } MsnClientCaps; typedef enum { - MSN_CLIENT_EXT_CAP_RTC_VIDEO = 0x10, - MSN_CLIENT_EXT_CAP_P2PV2 = 0x20 + MSN_EXT_CAP_SMS_ONLY = 0x1, + MSN_EXT_CAP_VOICE_OVER_MSNP = 0x2, + MSN_EXT_CAP_UUCP_SIP = 0x4, + MSN_EXT_CAP_APP_MSGS = 0x8, + MSN_EXT_CAP_RTC_VIDEO = 0x10, + MSN_EXT_CAP_P2PV2 = 0x20, + MSN_EXT_CAP_AUTH_WEBIM = 0x40, + MSN_EXT_CAP_1ON1_VIA_GROUP = 0x80, + MSN_EXT_CAP_OFFLINEIM = 0x100, + MSN_EXT_CAP_SHARING_VIDEO = 0x200, + MSN_EXT_CAP_NUDGE = 0x400, + MSN_EXT_CAP_CIRCLE_VOICEIM = 0x800, + MSN_EXT_CAP_SHARING = 0x1000, + MSN_EXT_CAP_P2P_MIXER_RELAY = 0x8000, + MSN_EXT_CAP_CONV_WINDOW_FT = 0x20000, + MSN_EXT_CAP_VIDEO_16x9 = 0x40000, + MSN_EXT_CAP_P2P_ENVELOPE = 0x80000, + MSN_EXT_CAP_YAHOOIM_DISABLE = 0x400000, + MSN_EXT_CAP_SIP_TUNNELv2 = 0x800000, + MSN_EXT_CAP_VOICE_CLIP_WMA = 0x1000000, + MSN_EXT_CAP_VOICE_CLIP_CIRCLEIM = 0x2000000, + MSN_EXT_CAP_SOCIAL_NEWS = 0x4000000, + MSN_EXT_CAP_CUSTOM_SMILEY = 0x8000000, + MSN_EXT_CAP_UTF8_MOODS = 0x10000000, + MSN_EXT_CAP_FTURN = 0x20000000, + MSN_EXT_CAP_P4_ACTIVITY = 0x40000000, + MSN_EXT_CAP_MUC = 0x80000000 } MsnClientExtCaps; typedef enum @@ -68,7 +99,8 @@ MSN_CLIENT_VER_8_1 = 0x70, /* MSNC7 */ MSN_CLIENT_VER_8_5 = 0x80, /* MSNC8 */ MSN_CLIENT_VER_9_0 = 0x90, /* MSNC9 */ - MSN_CLIENT_VER_14_0 = 0xA0 /* MSNC10 */ + MSN_CLIENT_VER_14_0 = 0xA0, /* MSNC10 */ + MSN_CLIENT_VER_15_0 = 0xB0 /* MSNC11 */ } MsnClientVerId; #include "internal.h" @@ -109,7 +141,7 @@ #define MSN_NUDGE 0 #define MSN_CLIENT_ID_VERSION MSN_CLIENT_VER_9_0 -#define MSN_CLIENT_ID_CAPABILITIES (MSN_CLIENT_CAP_PACKET|MSN_CLIENT_CAP_INK_GIF|MSN_CLIENT_CAP_VOICEIM) +#define MSN_CLIENT_ID_CAPABILITIES (MSN_CAP_PACKET|MSN_CAP_INK_GIF|MSN_CAP_VOICEIM) #define MSN_CLIENT_ID_EXT_CAPS (0) #define MSN_CLIENT_ID \ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/notification.c Mon Apr 25 20:13:05 2011 +0000 @@ -1099,7 +1099,7 @@ msn_user_set_object(user, msnobj); - user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); + user->mobile = (clientid & MSN_CAP_MOBILE_ON) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); msn_user_set_clientid(user, clientid); msn_user_set_extcaps(user, extcaps); msn_user_set_network(user, networkid); @@ -1186,34 +1186,40 @@ id = xmlnode_get_attrib(msg, "id"); - if (id && !strcmp(id, "407")) { + if (id && strcmp(id, "1")) { PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, gc->account); if (conv != NULL) { - purple_conversation_write(conv, NULL, - _("Mobile message was not sent because it was too long."), + const char *error; + if (!strcmp(id, "407")) + error = _("Mobile message was not sent because it was too long."); + else + error = _("Mobile message was not sent because an unknown error occurred."); + + purple_conversation_write(conv, NULL, error, PURPLE_MESSAGE_ERROR, time(NULL)); if ((id = xmlnode_get_attrib(payloadNode, "id")) != NULL) { unsigned int trId = atol(id); MsnTransaction *trans; - MsnMessage *msg; trans = msn_history_find(cmdproc->history, trId); - msg = (MsnMessage *)trans->data; - - if (msg) { - char *body_str = msn_message_to_string(msg); - char *body_enc = g_markup_escape_text(body_str, -1); - - purple_conversation_write(conv, NULL, body_enc, - PURPLE_MESSAGE_RAW, time(NULL)); - - g_free(body_str); - g_free(body_enc); - msn_message_unref(msg); - trans->data = NULL; + if (trans) { + MsnMessage *msg = (MsnMessage *)trans->data; + + if (msg) { + char *body_str = msn_message_to_string(msg); + char *body_enc = g_markup_escape_text(body_str, -1); + + purple_conversation_write(conv, NULL, body_enc, + PURPLE_MESSAGE_RAW, time(NULL)); + + g_free(body_str); + g_free(body_enc); + msn_message_unref(msg); + trans->data = NULL; + } } } } @@ -1274,7 +1280,7 @@ else extcaps = 0; - user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); + user->mobile = (clientid & MSN_CAP_MOBILE_ON) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); msn_user_set_clientid(user, clientid); msn_user_set_extcaps(user, extcaps); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/oim.c --- a/libpurple/protocols/msn/oim.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/oim.c Mon Apr 25 20:13:05 2011 +0000 @@ -175,7 +175,8 @@ if (faultcode_str) { if (g_str_equal(faultcode_str, "q0:BadContextToken") || - g_str_equal(faultcode_str, "AuthenticationFailed")) + g_str_equal(faultcode_str, "AuthenticationFailed") || + g_str_equal(faultcode_str, "s:AuthenticationFailed")) need_token_update = TRUE; else if (g_str_equal(faultcode_str, "q0:AuthenticationFailed") && xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/p2p.c --- a/libpurple/protocols/msn/p2p.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/p2p.c Mon Apr 25 20:13:05 2011 +0000 @@ -23,72 +23,229 @@ */ #include "internal.h" +#include "debug.h" #include "p2p.h" +#include "tlv.h" #include "msnutils.h" MsnP2PInfo * -msn_p2p_info_new(void) +msn_p2p_info_new(MsnP2PVersion version) { - return g_new0(MsnP2PInfo, 1); + MsnP2PInfo *info = g_new0(MsnP2PInfo, 1); + info->version = version; + + switch (version) { + case MSN_P2P_VERSION_ONE: + case MSN_P2P_VERSION_TWO: + /* Nothing to do */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", version); + g_free(info); + info = NULL; + } + + return info; } MsnP2PInfo * msn_p2p_info_dup(MsnP2PInfo *info) { MsnP2PInfo *new_info = g_new0(MsnP2PInfo, 1); - *new_info = *info; + + new_info->version = info->version; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + *new_info = *info; + break; + + case MSN_P2P_VERSION_TWO: + *new_info = *info; + new_info->header.v2.header_tlv = msn_tlvlist_copy(info->header.v2.header_tlv); + new_info->header.v2.data_tlv = msn_tlvlist_copy(info->header.v2.data_tlv); + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + g_free(new_info); + new_info = NULL; + } + return new_info; } void msn_p2p_info_free(MsnP2PInfo *info) { + switch (info->version) { + case MSN_P2P_VERSION_ONE: + /* Nothing to do! */ + break; + + case MSN_P2P_VERSION_TWO: + msn_tlvlist_free(info->header.v2.header_tlv); + msn_tlvlist_free(info->header.v2.data_tlv); + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + g_free(info); } size_t -msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire) +msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire, size_t max_len) { - MsnP2PHeader *header; + size_t len = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: { + MsnP2PHeader *header = &info->header.v1; + + if (max_len < P2P_PACKET_HEADER_SIZE) { + /* Invalid packet length */ + len = 0; + break; + } - header = &info->header; + header->session_id = msn_pop32le(wire); + header->id = msn_pop32le(wire); + header->offset = msn_pop64le(wire); + header->total_size = msn_pop64le(wire); + header->length = msn_pop32le(wire); + header->flags = msn_pop32le(wire); + header->ack_id = msn_pop32le(wire); + header->ack_sub_id = msn_pop32le(wire); + header->ack_size = msn_pop64le(wire); + + len = P2P_PACKET_HEADER_SIZE; + break; + } + + case MSN_P2P_VERSION_TWO: { + MsnP2Pv2Header *header = &info->header.v2; - header->session_id = msn_pop32le(wire); - header->id = msn_pop32le(wire); - header->offset = msn_pop64le(wire); - header->total_size = msn_pop64le(wire); - header->length = msn_pop32le(wire); - header->flags = msn_pop32le(wire); - header->ack_id = msn_pop32le(wire); - header->ack_sub_id = msn_pop32le(wire); - header->ack_size = msn_pop64le(wire); + header->header_len = msn_pop8(wire); + header->opcode = msn_pop8(wire); + header->message_len = msn_pop16be(wire); + header->base_id = msn_pop32be(wire); + if (header->header_len + header->message_len + P2P_PACKET_FOOTER_SIZE > max_len) { + /* Invalid header and data length */ + len = 0; + break; + } + + if (header->header_len > 8) { + header->header_tlv = msn_tlvlist_read(wire, header->header_len - 8); + wire += header->header_len - 8; + } + + if (header->message_len > 0) { + /* Parse Data packet */ - return P2P_PACKET_HEADER_SIZE; + header->data_header_len = msn_pop8(wire); + if (header->data_header_len > header->message_len) { + /* Invalid data header length */ + len = 0; + break; + } + header->data_tf = msn_pop8(wire); + header->package_number = msn_pop16be(wire); + header->session_id = msn_pop32be(wire); + + if (header->data_header_len > 8) { + header->data_tlv = msn_tlvlist_read(wire, header->data_header_len - 8); + wire += header->data_header_len - 8; + } + } + + len = header->header_len + header->message_len; + + break; + } + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return len; } char * msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len) { - MsnP2PHeader *header; - char *wire; + char *wire = NULL; char *tmp; - header = &info->header; - tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE); + switch (info->version) { + case MSN_P2P_VERSION_ONE: { + MsnP2PHeader *header = &info->header.v1; + tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE); + + msn_push32le(tmp, header->session_id); + msn_push32le(tmp, header->id); + msn_push64le(tmp, header->offset); + msn_push64le(tmp, header->total_size); + msn_push32le(tmp, header->length); + msn_push32le(tmp, header->flags); + msn_push32le(tmp, header->ack_id); + msn_push32le(tmp, header->ack_sub_id); + msn_push64le(tmp, header->ack_size); + + if (len) + *len = P2P_PACKET_HEADER_SIZE; + + break; + } + + case MSN_P2P_VERSION_TWO: { + MsnP2Pv2Header *header = &info->header.v2; + + if (header->header_tlv != NULL) + header->header_len = msn_tlvlist_size(header->header_tlv) + 8; + else + header->header_len = 8; - msn_push32le(tmp, header->session_id); - msn_push32le(tmp, header->id); - msn_push64le(tmp, header->offset); - msn_push64le(tmp, header->total_size); - msn_push32le(tmp, header->length); - msn_push32le(tmp, header->flags); - msn_push32le(tmp, header->ack_id); - msn_push32le(tmp, header->ack_sub_id); - msn_push64le(tmp, header->ack_size); + if (header->data_tlv != NULL) + header->data_header_len = msn_tlvlist_size(header->data_tlv) + 8; + else + header->data_header_len = 8; + + tmp = wire = g_new(char, header->header_len + header->data_header_len); + + msn_push8(tmp, header->header_len); + msn_push8(tmp, header->opcode); + msn_push16be(tmp, header->data_header_len + header->message_len); + msn_push32be(tmp, header->base_id); + + if (header->header_tlv != NULL) { + msn_tlvlist_write(tmp, header->header_len - 8, header->header_tlv); + tmp += header->header_len - 8; + } - if (len) - *len = P2P_PACKET_HEADER_SIZE; + msn_push8(tmp, header->data_header_len); + msn_push8(tmp, header->data_tf); + msn_push16be(tmp, header->package_number); + msn_push32be(tmp, header->session_id); + + if (header->data_tlv != NULL) { + msn_tlvlist_write(tmp, header->data_header_len - 8, header->data_tlv); + tmp += header->data_header_len - 8; + } + + if (len) + *len = header->header_len + header->data_header_len; + + break; + } + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } return wire; @@ -127,15 +284,30 @@ void msn_p2p_info_to_string(MsnP2PInfo *info, GString *str) { - g_string_append_printf(str, "Session ID: %u\r\n", info->header.session_id); - g_string_append_printf(str, "ID: %u\r\n", info->header.id); - g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", info->header.offset); - g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", info->header.total_size); - g_string_append_printf(str, "Length: %u\r\n", info->header.length); - g_string_append_printf(str, "Flags: 0x%x\r\n", info->header.flags); - g_string_append_printf(str, "ACK ID: %u\r\n", info->header.ack_id); - g_string_append_printf(str, "SUB ID: %u\r\n", info->header.ack_sub_id); - g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", info->header.ack_size); + switch (info->version) { + case MSN_P2P_VERSION_ONE: { + MsnP2PHeader *header = &info->header.v1; + g_string_append_printf(str, "Session ID: %u\r\n", header->session_id); + g_string_append_printf(str, "ID: %u\r\n", header->id); + g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", header->offset); + g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", header->total_size); + g_string_append_printf(str, "Length: %u\r\n", header->length); + g_string_append_printf(str, "Flags: 0x%x\r\n", header->flags); + g_string_append_printf(str, "ACK ID: %u\r\n", header->ack_id); + g_string_append_printf(str, "SUB ID: %u\r\n", header->ack_sub_id); + g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", header->ack_size); + + break; + } + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + g_string_append_printf(str, "Footer: 0x%08X\r\n", info->footer.value); } @@ -150,67 +322,232 @@ gboolean msn_p2p_info_is_valid(MsnP2PInfo *info) { - return info->header.total_size >= info->header.length; + gboolean valid = FALSE; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + valid = info->header.v1.total_size >= info->header.v1.length; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return valid; } gboolean msn_p2p_info_is_final(MsnP2PInfo *info) { - return info->header.offset + info->header.length >= info->header.total_size; + gboolean final = FALSE; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + final = info->header.v1.offset + info->header.v1.length >= info->header.v1.total_size; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return final; } guint32 msn_p2p_info_get_session_id(MsnP2PInfo *info) { - return info->header.session_id; + guint32 session_id = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + session_id = info->header.v1.session_id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return session_id; } guint32 msn_p2p_info_get_id(MsnP2PInfo *info) { - return info->header.id; + guint32 id = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + id = info->header.v1.id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return id; } guint64 msn_p2p_info_get_offset(MsnP2PInfo *info) { - return info->header.offset; + guint64 offset = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + offset = info->header.v1.offset; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return offset; } guint64 msn_p2p_info_get_total_size(MsnP2PInfo *info) { - return info->header.total_size; + guint64 total_size = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + total_size = info->header.v1.total_size; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return total_size; } guint32 msn_p2p_info_get_length(MsnP2PInfo *info) { - return info->header.length; + guint32 length = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + length = info->header.v1.length; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return length; } guint32 msn_p2p_info_get_flags(MsnP2PInfo *info) { - return info->header.flags; + guint32 flags = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + flags = info->header.v1.flags; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return flags; } guint32 msn_p2p_info_get_ack_id(MsnP2PInfo *info) { - return info->header.ack_id; + guint32 ack_id = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + ack_id = info->header.v1.ack_id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return ack_id; } guint32 msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info) { - return info->header.ack_sub_id; + guint32 ack_sub_id = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + ack_sub_id = info->header.v1.ack_sub_id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return ack_sub_id; } guint64 msn_p2p_info_get_ack_size(MsnP2PInfo *info) { - return info->header.ack_size; + guint64 ack_size = 0; + + switch (info->version) { + case MSN_P2P_VERSION_ONE: + ack_size = info->header.v1.ack_size; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + + return ack_size; } guint32 @@ -222,55 +559,156 @@ void msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id) { - info->header.session_id = session_id; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.session_id = session_id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + } void msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id) { - info->header.id = id; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.id = id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } + } void msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset) { - info->header.offset = offset; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.offset = offset; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } } void msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size) { - info->header.total_size = total_size; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.total_size = total_size; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } } void msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length) { - info->header.length = length; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.length = length; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } } void msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags) { - info->header.flags = flags; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.flags = flags; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } } void msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id) { - info->header.ack_id = ack_id; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.ack_id = ack_id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } } void msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id) { - info->header.ack_sub_id = ack_sub_id; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.ack_sub_id = ack_sub_id; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } } void msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size) { - info->header.ack_size = ack_size; + switch (info->version) { + case MSN_P2P_VERSION_ONE: + info->header.v1.ack_size = ack_size; + break; + + case MSN_P2P_VERSION_TWO: + /* Nothing to do! */ + break; + + default: + purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version); + } } void diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/p2p.h --- a/libpurple/protocols/msn/p2p.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/p2p.h Mon Apr 25 20:13:05 2011 +0000 @@ -50,6 +50,13 @@ guint8 opcode; guint16 message_len; guint32 base_id; + GSList *header_tlv; + guint8 data_header_len; + guint8 data_tf; + guint16 package_number; + guint32 session_id; + GSList *data_tlv; +/* guint8 body[1]; */ } MsnP2Pv2Header; typedef struct @@ -58,8 +65,18 @@ } MsnP2PFooter; #define P2P_PACKET_FOOTER_SIZE (1 * 4) +typedef enum +{ + MSN_P2P_VERSION_ONE = 0, + MSN_P2P_VERSION_TWO = 1, +} MsnP2PVersion; + typedef struct { - MsnP2PHeader header; + MsnP2PVersion version; + union { + MsnP2PHeader v1; + MsnP2Pv2Header v2; + } header; MsnP2PFooter footer; } MsnP2PInfo; @@ -93,8 +110,15 @@ P2P_APPID_DISPLAY = 0xC /**< Display Image */ } MsnP2PAppId; +typedef enum +{ + P2P_OPCODE_NONE = 0x00, + P2P_OPCODE_SYN = 0x01, + P2P_OPCODE_RAK = 0x02 +} MsnP2Pv2OpCode; + MsnP2PInfo * -msn_p2p_info_new(void); +msn_p2p_info_new(MsnP2PVersion version); MsnP2PInfo * msn_p2p_info_dup(MsnP2PInfo *info); @@ -103,7 +127,7 @@ msn_p2p_info_free(MsnP2PInfo *info); size_t -msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire); +msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire, size_t max_len); char * msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/session.c --- a/libpurple/protocols/msn/session.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/session.c Mon Apr 25 20:13:05 2011 +0000 @@ -46,7 +46,7 @@ session->user = msn_user_new(session->userlist, purple_account_get_username(account), NULL); - msn_userlist_add_user(session->userlist, msn_user_ref(session->user)); + msn_userlist_add_user(session->userlist, session->user); session->oim = msn_oim_new(session); session->protocol_ver = 0; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/slplink.c --- a/libpurple/protocols/msn/slplink.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/slplink.c Mon Apr 25 20:13:05 2011 +0000 @@ -289,7 +289,7 @@ /* Maybe we will want to create a new msg for this slpmsg instead of * reusing the same one all the time. */ info = slpmsg->p2p_info; - part = msn_slpmsgpart_new(info); + part = msn_slpmsgpart_new(msn_p2p_info_dup(info)); part->ack_data = slpmsg; real_size = (msn_p2p_info_get_flags(info) == P2P_ACK) ? 0 : slpmsg->size; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/slpmsg.c --- a/libpurple/protocols/msn/slpmsg.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/slpmsg.c Mon Apr 25 20:13:05 2011 +0000 @@ -48,7 +48,7 @@ else slpmsg->slplink = NULL; - slpmsg->p2p_info = msn_p2p_info_new(); + slpmsg->p2p_info = msn_p2p_info_new(MSN_P2P_VERSION_ONE); return slpmsg; } diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/slpmsg_part.c --- a/libpurple/protocols/msn/slpmsg_part.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/slpmsg_part.c Mon Apr 25 20:13:05 2011 +0000 @@ -34,8 +34,7 @@ part = g_new0(MsnSlpMessagePart, 1); - if (info) - part->info = msn_p2p_info_dup(info); + part->info = info; part->ack_cb = msn_slpmsgpart_ack; part->nak_cb = msn_slpmsgpart_nak; @@ -46,19 +45,20 @@ MsnSlpMessagePart *msn_slpmsgpart_new_from_data(const char *data, size_t data_len) { MsnSlpMessagePart *part; + MsnP2PInfo *info; size_t len; int body_len; - if (data_len < P2P_PACKET_HEADER_SIZE) { + info = msn_p2p_info_new(MSN_P2P_VERSION_ONE); + + /* Extract the binary SLP header */ + len = msn_p2p_header_from_wire(info, data, data_len); + if (len == 0) { + msn_p2p_info_free(info); return NULL; } - - part = msn_slpmsgpart_new(NULL); - part->info = msn_p2p_info_new(); - - /* Extract the binary SLP header */ - len = msn_p2p_header_from_wire(part->info, data); data += len; + part = msn_slpmsgpart_new(info); /* Extract the body */ body_len = data_len - len - P2P_PACKET_FOOTER_SIZE; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/state.c --- a/libpurple/protocols/msn/state.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/state.c Mon Apr 25 20:13:05 2011 +0000 @@ -217,11 +217,11 @@ if (client_type) { if (strcmp(client_type, "phone") == 0 || strcmp(client_type, "handheld") == 0) { - caps |= MSN_CLIENT_CAP_WIN_MOBILE; + caps |= MSN_CAP_VIA_MOBILE; } else if (strcmp(client_type, "web") == 0) { - caps |= MSN_CLIENT_CAP_WEBMSGR; + caps |= MSN_CAP_VIA_WEBIM; } else if (strcmp(client_type, "bot") == 0) { - caps |= MSN_CLIENT_CAP_BOT; + caps |= MSN_CAP_BOT; } /* MSN doesn't a "console" type... What, they have no ncurses UI? :-) */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/switchboard.c --- a/libpurple/protocols/msn/switchboard.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/switchboard.c Mon Apr 25 20:13:05 2011 +0000 @@ -265,12 +265,6 @@ return; } - /* Don't add ourselves either... */ - if (g_str_equal(passport, purple_account_get_username(account))) { - g_free(passport); - return; - } - if (!msnuser) { purple_debug_info("msn","User %s is not on our list.\n", passport); msnuser = msn_user_new(userlist, passport, NULL); @@ -732,6 +726,7 @@ g_return_if_fail(msg != NULL); msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_NAK); + cmd->trans->data = NULL; } static void @@ -749,6 +744,7 @@ if (swboard) swboard->ack_list = g_list_remove(swboard->ack_list, msg); msn_message_unref(msg); + cmd->trans->data = NULL; } static void diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/tlv.c --- a/libpurple/protocols/msn/tlv.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/tlv.c Mon Apr 25 20:13:05 2011 +0000 @@ -46,7 +46,7 @@ } static GSList * -msn_tlv_read(GSList *list, char *bs, size_t *bs_len) +msn_tlv_read(GSList *list, const char *bs, size_t *bs_len) { guint8 type, length; msn_tlv_t *tlv; @@ -76,7 +76,7 @@ } GSList * -msn_tlvlist_read(char *bs, size_t bs_len) +msn_tlvlist_read(const char *bs, size_t bs_len) { GSList *list = NULL; @@ -302,10 +302,10 @@ } } +int +msn_tlvlist_write(char *bs, size_t bs_len, GSList *list) +{ #if 0 -int -msn_tlvlist_write(ByteStream *bs, GSList **list) -{ int goodbuflen; GSList *cur; msn_tlv_t *tlv; @@ -325,9 +325,9 @@ byte_stream_putraw(bs, tlv->value, tlv->length); } - return 1; /* TODO: This is a nonsensical return */ +#endif + return 0; /* TODO: This is a nonsensical return */ } -#endif msn_tlv_t * msn_tlv_gettlv(GSList *list, const guint16 type, const int nth) diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/tlv.h --- a/libpurple/protocols/msn/tlv.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/tlv.h Mon Apr 25 20:13:05 2011 +0000 @@ -46,13 +46,13 @@ guint32 msn_tlv_get32(GSList *list, const guint16 type, const int nth); /* TLV list handling functions */ -GSList *msn_tlvlist_read(char *bs, size_t bs_len); +GSList *msn_tlvlist_read(const char *bs, size_t bs_len); GSList *msn_tlvlist_copy(GSList *orig); int msn_tlvlist_count(GSList *list); size_t msn_tlvlist_size(GSList *list); gboolean msn_tlvlist_equal(GSList *one, GSList *two); -int msn_tlvlist_write(char *bs, size_t bs_len, GSList **list); +int msn_tlvlist_write(char *bs, size_t bs_len, GSList *list); void msn_tlvlist_free(GSList *list); int msn_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const char *value); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/user.c --- a/libpurple/protocols/msn/user.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/user.c Mon Apr 25 20:13:05 2011 +0000 @@ -223,7 +223,10 @@ { g_return_val_if_fail(user != NULL, FALSE); - if (user->friendly_name && name && (!strcmp(user->friendly_name, name) || + if (!name) + return FALSE; + + if (user->friendly_name && (!strcmp(user->friendly_name, name) || !strcmp(user->passport, name))) return FALSE; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/user.h --- a/libpurple/protocols/msn/user.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/user.h Mon Apr 25 20:13:05 2011 +0000 @@ -28,13 +28,18 @@ typedef enum { - MSN_NETWORK_UNKNOWN = 0x00, - MSN_NETWORK_PASSPORT = 0x01, - MSN_NETWORK_COMMUNICATOR = 0x02, - MSN_NETWORK_MOBILE = 0x04, - MSN_NETWORK_MNI = 0x08, - MSN_NETWORK_SMTP = 0x10, - MSN_NETWORK_YAHOO = 0x20 + MSN_NETWORK_UNKNOWN = 0, + MSN_NETWORK_PASSPORT = 1, + MSN_NETWORK_COMMUNICATOR = 2, + MSN_NETWORK_MOBILE = 4, + MSN_NETWORK_MNI = 8, + MSN_NETWORK_CIRCLE = 9, + MSN_NETWORK_TEMP_GROUP = 10, + MSN_NETWORK_CID = 11, + MSN_NETWORK_CONNECT = 13, + MSN_NETWORK_REMOTE = 14, + MSN_NETWORK_SMTP = 16, + MSN_NETWORK_YAHOO = 32 } MsnNetwork; /** @@ -144,7 +149,7 @@ * @param passport The initial passport. * @param stored_name The initial stored name. * - * @return A new user structure. + * @return A new user structure. It will have a reference count of 1. */ MsnUser *msn_user_new(MsnUserList *userlist, const char *passport, const char *friendly_name); @@ -159,7 +164,8 @@ MsnUser *msn_user_ref(MsnUser *user); /** - * Decrement the reference count. + * Decrement the reference count. When the count reaches 0 the object is + * automatically freed. * * @param user The user */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/userlist.c --- a/libpurple/protocols/msn/userlist.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/userlist.c Mon Apr 25 20:13:05 2011 +0000 @@ -236,17 +236,18 @@ } MsnUser * -msn_userlist_find_add_user(MsnUserList *userlist,const char *passport,const char *userName) +msn_userlist_find_add_user(MsnUserList *userlist, const char *passport, const char *friendly_name) { MsnUser *user; user = msn_userlist_find_user(userlist, passport); if (user == NULL) { - user = msn_user_new(userlist, passport, userName); + user = msn_user_new(userlist, passport, friendly_name); msn_userlist_add_user(userlist, user); + msn_user_unref(user); } else { - msn_user_set_friendly_name(user, userName); + msn_user_set_friendly_name(user, friendly_name); } return user; } @@ -254,6 +255,7 @@ void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user) { + msn_user_ref(user); userlist->users = g_list_prepend(userlist->users, user); } @@ -261,6 +263,7 @@ msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user) { userlist->users = g_list_remove(userlist->users, user); + msn_user_unref(user); } MsnUser * @@ -287,7 +290,7 @@ MsnUser * msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid) { - GList *l; + GList *l; g_return_val_if_fail(uid != NULL, NULL); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/msn/userlist.h --- a/libpurple/protocols/msn/userlist.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/msn/userlist.h Mon Apr 25 20:13:05 2011 +0000 @@ -73,7 +73,7 @@ MsnUser * msn_userlist_find_user(MsnUserList *userlist, const char *passport); MsnUser * msn_userlist_find_add_user(MsnUserList *userlist, - const char *passport, const char *userName); + const char *passport, const char *friendly_name); MsnUser * msn_userlist_find_user_with_id(MsnUserList *userlist, const char *uid); MsnUser * msn_userlist_find_user_with_mobile_phone(MsnUserList *userlist, const char *number); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/Makefile.am --- a/libpurple/protocols/mxit/Makefile.am Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/Makefile.am Mon Apr 25 20:13:05 2011 +0000 @@ -33,7 +33,9 @@ roster.c \ roster.h \ splashscreen.c \ - splashscreen.h + splashscreen.h \ + voicevideo.c \ + voicevideo.h AM_CFLAGS = $(st) diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/Makefile.mingw --- a/libpurple/protocols/mxit/Makefile.mingw Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/Makefile.mingw Mon Apr 25 20:13:05 2011 +0000 @@ -51,7 +51,8 @@ profile.c \ protocol.c \ roster.c \ - splashscreen.c + splashscreen.c \ + voicevideo.c OBJECTS = $(C_SRC:%.c=%.o) diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/actions.c --- a/libpurple/protocols/mxit/actions.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/actions.c Mon Apr 25 20:13:05 2011 +0000 @@ -314,12 +314,11 @@ { char version[256]; - g_snprintf( version, sizeof( version ), "MXit libPurple Plugin v%s\n" + g_snprintf( version, sizeof( version ), "MXit Client Protocol v%i.%i\n\n" "Author:\nPieter Loubser\n\n" "Contributors:\nAndrew Victor\n\n" "Testers:\nBraeme Le Roux\n\n", - MXIT_PLUGIN_VERSION, ( MXIT_CP_PROTO_VESION / 10 ), ( MXIT_CP_PROTO_VESION % 10 ) ); mxit_popup( PURPLE_NOTIFY_MSG_INFO, _( "About" ), version ); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/chunk.c --- a/libpurple/protocols/mxit/chunk.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/chunk.c Mon Apr 25 20:13:05 2011 +0000 @@ -406,10 +406,9 @@ * @param chunkdata Chunked-data buffer * @param mxitId The username who's avatar to download * @param avatarId The Id of the avatar image (as string) - * @param imgsize The resolution of the avatar image * @return The number of bytes encoded in the buffer */ -int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId, unsigned int imgsize ) +int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId ) { int pos = 0; @@ -432,7 +431,7 @@ pos += add_int16( &chunkdata[pos], 1 ); /* image size [4 bytes] */ - pos += add_int32( &chunkdata[pos], imgsize ); + pos += add_int32( &chunkdata[pos], MXIT_AVATAR_SIZE ); return pos; } diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/chunk.h --- a/libpurple/protocols/mxit/chunk.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/chunk.h Mon Apr 25 20:13:05 2011 +0000 @@ -152,7 +152,7 @@ int mxit_chunk_create_get( char* chunkdata, const char* fileid, int filesize, int offset ); int mxit_chunk_create_received( char* chunkdata, const char* fileid, unsigned char status ); int mxit_chunk_create_set_avatar( char* chunkdata, const unsigned char* data, int datalen ); -int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId, unsigned int imgsize ); +int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId ); /* Decode chunk */ void mxit_chunk_parse_offer( char* chunkdata, int datalen, struct offerfile_chunk* offer ); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/formcmds.c --- a/libpurple/protocols/mxit/formcmds.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/formcmds.c Mon Apr 25 20:13:05 2011 +0000 @@ -47,7 +47,11 @@ MXIT_CMD_REPLY, /* Reply (reply) */ MXIT_CMD_PLATREQ, /* Platform Request (platreq) */ MXIT_CMD_SELECTCONTACT, /* Select Contact (selc) */ - MXIT_CMD_IMAGE /* Inline image (img) */ + MXIT_CMD_IMAGE, /* Inline image (img) */ + MXIT_CMD_SCREENCONFIG, /* Chat-screen config (csc) */ + MXIT_CMD_SCREENINFO, /* Chat-screen info (csi) */ + MXIT_CMD_IMAGESTRIP, /* Image Strip (is) */ + MXIT_CMD_TABLE /* Table (tbl) */ } MXitCommandType; @@ -87,7 +91,7 @@ goto done; } - /* lets first see if we dont have the inline image already in cache */ + /* lets first see if we don't have the inline image already in cache */ if (g_hash_table_lookup(iireq->mx->session->iimages, iireq->url)) { /* inline image found in the cache, so we just ignore this reply */ goto done; @@ -149,8 +153,16 @@ else if (strcmp(type, "selc") == 0) /* select contact */ return MXIT_CMD_SELECTCONTACT; } - else if (strcmp(op, "img") == 0) - return MXIT_CMD_IMAGE; + else if (strcmp(op, "img") == 0) /* inline image */ + return MXIT_CMD_IMAGE; + else if (strcmp(op, "csc") == 0) /* chat-screen config */ + return MXIT_CMD_SCREENCONFIG; + else if (strcmp(op, "csi") == 0) /* chat-screen info */ + return MXIT_CMD_SCREENINFO; + else if (strcmp(op, "is") == 0) /* image-strip */ + return MXIT_CMD_IMAGESTRIP; + else if (strcmp(op, "tbl") == 0) /* table */ + return MXIT_CMD_TABLE; } return MXIT_CMD_UNKNOWN; @@ -333,7 +345,7 @@ g_string_append_printf(msg, "%s%s>", MXIT_II_TAG, iireq->url); mx->got_img = TRUE; - /* lets first see if we dont have the inline image already in cache */ + /* lets first see if we don't have the inline image already in cache */ if (g_hash_table_lookup(mx->session->iimages, iireq->url)) { /* inline image found in the cache, so we do not have to request it from the web */ g_free(iireq); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/login.c --- a/libpurple/protocols/mxit/login.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/login.c Mon Apr 25 20:13:05 2011 +0000 @@ -84,7 +84,7 @@ session->iimages = g_hash_table_new( g_str_hash, g_str_equal ); session->rx_state = RX_STATE_RLEN; session->http_interval = MXIT_HTTP_POLL_MIN; - session->http_last_poll = time( NULL ); + session->http_last_poll = mxit_now_milli(); return session; } @@ -106,7 +106,7 @@ purple_connection_update_progress( session->con, _( "Logging In..." ), 2, 4 ); /* create a timer to send a ping packet if the connection is idle */ - session->last_tx = time( NULL ); + session->last_tx = mxit_now_milli(); /* encrypt the user password */ session->encpwd = mxit_encrypt_password( session ); @@ -141,9 +141,10 @@ } /* This timer might already exist if we're registering a new account */ - if ( session->q_timer == 0 ) + if ( session->q_timer == 0 ) { /* start the tx queue manager timer */ - session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue, session ); + session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue_slow, session ); + } } @@ -238,7 +239,7 @@ /* nickname */ str = purple_request_fields_get_string( fields, "nickname" ); if ( ( !str ) || ( strlen( str ) < 3 ) ) { - err = _( "The Display Name you entered is invalid." ); + err = _( "The Display Name you entered is too short." ); goto out; } g_strlcpy( profile->nickname, str, sizeof( profile->nickname ) ); @@ -546,8 +547,8 @@ /* get state */ state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN ); - url = g_strdup_printf( "%s?type=getpid&sessionid=%s&login=%s&ver=%s&clientid=%s&cat=%s&chalresp=%s&cc=%s&loc=%s&path=%i&brand=%s&model=%s&h=%i&w=%i&ts=%li", - session->logindata->wapserver, session->logindata->sessionid, purple_url_encode( session->acc->username ), MXIT_CP_RELEASE, MXIT_CLIENT_ID, MXIT_CP_ARCH, + url = g_strdup_printf( "%s?type=getpid&sessionid=%s&login=%s&ver=%i.%i.%i&clientid=%s&cat=%s&chalresp=%s&cc=%s&loc=%s&path=%i&brand=%s&model=%s&h=%i&w=%i&ts=%li", + session->logindata->wapserver, session->logindata->sessionid, purple_url_encode( session->acc->username ), PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CLIENT_ID, MXIT_CP_ARCH, captcha_resp, session->logindata->cc, session->logindata->locale, ( state == MXIT_STATE_REGISTER1 ) ? 0 : 1, MXIT_CP_PLATFORM, MXIT_CP_OS, MXIT_CAPTCHA_HEIGHT, MXIT_CAPTCHA_WIDTH, time( NULL ) ); url_data = purple_util_fetch_url_request( url, TRUE, MXIT_HTTP_USERAGENT, TRUE, NULL, FALSE, mxit_cb_clientinfo2, session ); @@ -762,6 +763,12 @@ { purple_debug_info( MXIT_PLUGIN_ID, "mxit_reconnect\n" ); + /* remove the input cb function */ + if ( session->con->inpa ) { + purple_input_remove( session->con->inpa ); + session->con->inpa = 0; + } + /* close existing connection */ session->flags &= ~MXIT_FLAG_CONNECTED; purple_proxy_connect_cancel_with_handle( session->con ); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/mxit.c --- a/libpurple/protocols/mxit/mxit.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/mxit.c Mon Apr 25 20:13:05 2011 +0000 @@ -37,6 +37,7 @@ #include "filexfer.h" #include "actions.h" #include "multimx.h" +#include "voicevideo.h" #ifdef MXIT_LINK_CLICK @@ -524,7 +525,7 @@ if ( session->http ) return; - if ( session->last_tx <= time( NULL ) - MXIT_PING_INTERVAL ) { + if ( session->last_tx <= ( mxit_now_milli() - ( MXIT_PING_INTERVAL * 1000 ) ) ) { /* * this connection has been idle for too long, better ping * the server before it kills our connection. @@ -559,6 +560,8 @@ */ static void mxit_get_info( PurpleConnection *gc, const char *who ) { + PurpleBuddy* buddy; + struct contact* contact; struct MXitSession* session = (struct MXitSession*) gc->proto_data; const char* profilelist[] = { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_FULLNAME, CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_REGCOUNTRY, CP_PROFILE_LASTSEEN, @@ -566,6 +569,22 @@ purple_debug_info( MXIT_PLUGIN_ID, "mxit_get_info: '%s'\n", who ); + /* find the buddy information for this contact (reference: "libpurple/blist.h") */ + buddy = purple_find_buddy( session->acc, who ); + if ( !buddy ) { + purple_debug_warning( MXIT_PLUGIN_ID, "mxit_get_info: unable to find the buddy '%s'\n", who ); + return; + } + + contact = purple_buddy_get_protocol_data( buddy ); + if ( !contact ) + return; + + /* only MXit users have profiles */ + if ( contact->type != MXIT_TYPE_MXIT ) { + mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "No profile available" ), _( "This contact does not have a profile." ) ); + return; + } /* send profile request */ mxit_send_extprofile_request( session, who, ARRAY_SIZE( profilelist ), profilelist ); @@ -588,7 +607,33 @@ /*------------------------------------------------------------------------ - * Buddy list menu. + * Re-Invite was selected from the buddy-list menu. + * + * @param node The entry in the buddy list. + * @param ignored (not used) + */ +static void mxit_reinvite( PurpleBlistNode *node, gpointer ignored ) +{ + PurpleBuddy* buddy; + struct contact* contact; + PurpleConnection* gc; + struct MXitSession* session; + + buddy = (PurpleBuddy *)node; + gc = purple_account_get_connection( purple_buddy_get_account( buddy ) ); + session = gc->proto_data; + + contact = purple_buddy_get_protocol_data( (PurpleBuddy*) node ); + if ( !contact ) + return; + + /* send a new invite */ + mxit_send_invite( session, contact->username, contact->alias, contact->groupname ); +} + + +/*------------------------------------------------------------------------ + * Buddy-list menu. * * @param node The entry in the buddy list. */ @@ -597,6 +642,7 @@ PurpleBuddy* buddy; struct contact* contact; GList* m = NULL; + PurpleMenuAction* act; if ( !PURPLE_BLIST_NODE_IS_BUDDY( node ) ) return NULL; @@ -606,6 +652,12 @@ if ( !contact ) return NULL; + if ( ( contact->subtype == MXIT_SUBTYPE_DELETED ) || ( contact->subtype == MXIT_SUBTYPE_REJECTED ) || ( contact->subtype == MXIT_SUBTYPE_NONE ) ) { + /* contact is in Deleted, Rejected or None state */ + act = purple_menu_action_new( _( "Re-Invite" ), PURPLE_CALLBACK( mxit_reinvite ), NULL, NULL ); + m = g_list_append(m, act); + } + return m; } @@ -686,11 +738,13 @@ NULL, /* attention_types */ sizeof( PurplePluginProtocolInfo ), /* struct_size */ mxit_get_text_table, /* get_account_text_table */ - NULL, /* initiate_media */ - NULL, /* get_media_caps */ + mxit_media_initiate, /* initiate_media */ + mxit_media_caps, /* get_media_caps */ mxit_get_moods, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; @@ -706,7 +760,7 @@ MXIT_PLUGIN_ID, /* plugin id (must be unique) */ MXIT_PLUGIN_NAME, /* plugin name (this will be displayed in the UI) */ - MXIT_PLUGIN_VERSION, /* version of the plugin */ + DISPLAY_VERSION, /* version of the plugin */ MXIT_PLUGIN_SUMMARY, /* short summary of the plugin */ MXIT_PLUGIN_DESC, /* description of the plugin (can be long) */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/mxit.h --- a/libpurple/protocols/mxit/mxit.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/mxit.h Mon Apr 25 20:13:05 2011 +0000 @@ -63,13 +63,12 @@ /* Plugin details */ #define MXIT_PLUGIN_ID "prpl-loubserp-mxit" #define MXIT_PLUGIN_NAME "MXit" -#define MXIT_PLUGIN_VERSION "2.4.0" #define MXIT_PLUGIN_EMAIL "Pieter Loubser " #define MXIT_PLUGIN_WWW "http://www.mxit.com" #define MXIT_PLUGIN_SUMMARY "MXit Protocol Plugin" #define MXIT_PLUGIN_DESC "MXit" -#define MXIT_HTTP_USERAGENT "libpurple-"MXIT_PLUGIN_VERSION +#define MXIT_HTTP_USERAGENT "libpurple-"DISPLAY_VERSION /* default connection settings */ @@ -111,7 +110,6 @@ /* define this to enable the link clicking support */ #define MXIT_LINK_CLICK - #ifdef MXIT_LINK_CLICK #define MXIT_LINK_PREFIX "gopher://" #define MXIT_LINK_KEY "MXIT" @@ -137,10 +135,13 @@ unsigned int http_seqno; /* HTTP request sequence number */ guint http_timer_id; /* timer resource id (pidgin) */ int http_interval; /* poll inverval */ - time_t http_last_poll; /* the last time a poll has been sent */ + gint64 http_last_poll; /* the last time a poll has been sent */ guint http_handler; /* HTTP connection handler */ void* http_out_req; /* HTTP outstanding request */ + /* other servers */ + char voip_server[HOST_NAME_MAX]; /* voice/video server */ + /* client */ struct login_data* logindata; char* encpwd; /* encrypted password */ @@ -159,7 +160,7 @@ /* transmit */ struct tx_queue queue; /* transmit packet queue (FIFO mode) */ - time_t last_tx; /* timestamp of last packet sent */ + gint64 last_tx; /* timestamp of last packet sent */ int outack; /* outstanding ack packet */ guint q_timer; /* timer handler for managing queue */ @@ -169,7 +170,7 @@ unsigned int rx_i; /* receive buffer current index */ int rx_res; /* amount of bytes still outstanding for the current packet */ char rx_state; /* current receiver state */ - time_t last_rx; /* timestamp of last packet received */ + gint64 last_rx; /* timestamp of last packet received */ GList* active_chats; /* list of all our contacts we received messages from (active chats) */ /* groupchat */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/profile.c --- a/libpurple/protocols/mxit/profile.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/profile.c Mon Apr 25 20:13:05 2011 +0000 @@ -108,10 +108,10 @@ */ static const char* datetime( gint64 msecs ) { - time_t secs = msecs / 1000; + time_t secs = msecs / 1000; - struct tm t; - localtime_r( &secs, &t ); + struct tm t; + localtime_r( &secs, &t ); return purple_utf8_strftime( "%d-%m-%Y %H:%M:%S", &t ); } @@ -140,13 +140,10 @@ purple_notify_user_info_add_pair( info, _( "Display Name" ), profile->nickname ); purple_notify_user_info_add_pair( info, _( "Birthday" ), profile->birthday ); purple_notify_user_info_add_pair( info, _( "Gender" ), profile->male ? _( "Male" ) : _( "Female" ) ); -// purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) ); /* optional information */ -// purple_notify_user_info_add_pair( info, _( "Title" ), profile->title ); purple_notify_user_info_add_pair( info, _( "First Name" ), profile->firstname ); purple_notify_user_info_add_pair( info, _( "Last Name" ), profile->lastname ); -// purple_notify_user_info_add_pair( info, _( "Email" ), profile->email ); purple_notify_user_info_add_pair( info, _( "Country" ), profile->regcountry ); purple_notify_user_info_add_section_break( info ); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/protocol.c --- a/libpurple/protocols/mxit/protocol.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/protocol.c Mon Apr 25 20:13:05 2011 +0000 @@ -37,6 +37,7 @@ #include "login.h" #include "formcmds.h" #include "http.h" +#include "voicevideo.h" #define MXIT_MS_OFFSET 3 @@ -45,6 +46,18 @@ #define CP_REC_TERM ( ( session->http ) ? CP_HTTP_REC_TERM : CP_SOCK_REC_TERM ) +/*------------------------------------------------------------------------ + * return the current timestamp in milliseconds + */ +gint64 mxit_now_milli( void ) +{ + GTimeVal now; + + g_get_current_time( &now ); + + return ( ( now.tv_sec * 1000 ) + ( now.tv_usec / 1000 ) ); +} + /*------------------------------------------------------------------------ * Display a notification popup message to the user. @@ -411,7 +424,7 @@ } /* update the timestamp of the last-transmitted packet */ - session->last_tx = time( NULL ); + session->last_tx = mxit_now_milli(); /* * we need to remember that we are still waiting for the ACK from @@ -474,17 +487,13 @@ packet->datalen = datalen; - /* - * shortcut: first check if there are any commands still outstanding. - * if not, then we might as well just write this packet directly and - * skip the whole queueing thing - */ - if ( session->outack == 0 ) { - /* no outstanding ACKs, so we might as well write it directly */ + /* shortcut */ + if ( ( session->queue.count == 0 ) && ( session->outack == 0 ) ) { + /* the queue is empty and there are no outstanding acks so we can write it directly */ mxit_send_packet( session, packet ); } else { - /* ACK still outstanding, so we need to queue this request until we have the ACK */ + /* we need to queue this packet */ if ( ( packet->cmd == CP_CMD_PING ) || ( packet->cmd == CP_CMD_POLL ) ) { /* we do NOT queue HTTP poll nor socket ping packets */ @@ -503,42 +512,89 @@ /*------------------------------------------------------------------------ - * Callback to manage the packet send queue (send next packet, timeout's, etc). + * Manage the packet send queue (send next packet, timeout's, etc). * * @param session The MXit session object */ -gboolean mxit_manage_queue( gpointer user_data ) +static void mxit_manage_queue( struct MXitSession* session ) { - struct MXitSession* session = (struct MXitSession*) user_data; struct tx_packet* packet = NULL; + gint64 now = mxit_now_milli(); if ( !( session->flags & MXIT_FLAG_CONNECTED ) ) { /* we are not connected, so ignore the queue */ - return TRUE; + return; } else if ( session->outack > 0 ) { /* we are still waiting for an outstanding ACK from the MXit server */ - if ( session->last_tx <= time( NULL ) - MXIT_ACK_TIMEOUT ) { + if ( session->last_tx <= mxit_now_milli() - ( MXIT_ACK_TIMEOUT * 1000 ) ) { /* ack timeout! so we close the connection here */ purple_debug_info( MXIT_PLUGIN_ID, "mxit_manage_queue: Timeout awaiting ACK for command '%i'\n", session->outack ); purple_connection_error( session->con, _( "Timeout while waiting for a response from the MXit server." ) ); } - return TRUE; + return; + } + + /* + * the mxit server has flood detection and it prevents you from sending messages to fast. + * this is a self defense mechanism, a very annoying feature. so the client must ensure that + * it does not send messages too fast otherwise mxit will ignore the user for 30 seconds. + * this is what we are trying to avoid here.. + */ + if ( session->last_tx > ( now - MXIT_TX_DELAY ) ) { + /* we need to wait a little before sending the next packet, so schedule a wakeup call */ + gint64 tdiff = now - ( session->last_tx ); + guint delay = ( MXIT_TX_DELAY - tdiff ) + 9; + if ( delay <= 0 ) + delay = MXIT_TX_DELAY; + purple_timeout_add( delay, mxit_manage_queue_fast, session ); + } + else { + /* get the next packet from the queue to send */ + packet = pop_tx_packet( session ); + if ( packet != NULL ) { + /* there was a packet waiting to be sent to the server, now is the time to do something about it */ + + /* send the packet to MXit server */ + mxit_send_packet( session, packet ); + } } - - packet = pop_tx_packet( session ); - if ( packet != NULL ) { - /* there was a packet waiting to be sent to the server, now is the time to do something about it */ - - /* send the packet to MXit server */ - mxit_send_packet( session, packet ); - } - +} + + +/*------------------------------------------------------------------------ + * Slow callback to manage the packet send queue. + * + * @param session The MXit session object + */ +gboolean mxit_manage_queue_slow( gpointer user_data ) +{ + struct MXitSession* session = (struct MXitSession*) user_data; + + mxit_manage_queue( session ); + + /* continue running */ return TRUE; } /*------------------------------------------------------------------------ + * Fast callback to manage the packet send queue. + * + * @param session The MXit session object + */ +gboolean mxit_manage_queue_fast( gpointer user_data ) +{ + struct MXitSession* session = (struct MXitSession*) user_data; + + mxit_manage_queue( session ); + + /* stop running */ + return FALSE; +} + + +/*------------------------------------------------------------------------ * Callback to manage HTTP server polling (HTTP connections ONLY) * * @param session The MXit session object @@ -547,9 +603,9 @@ { struct MXitSession* session = (struct MXitSession*) user_data; gboolean poll = FALSE; - time_t now = time( NULL ); + gint64 now = mxit_now_milli(); int polldiff; - int rxdiff; + gint64 rxdiff; if ( !( session->flags & MXIT_FLAG_LOGGEDIN ) ) { /* we only poll if we are actually logged in */ @@ -579,7 +635,7 @@ if ( poll ) { /* send poll request */ - session->http_last_poll = time( NULL ); + session->http_last_poll = mxit_now_milli(); mxit_send_poll( session ); } @@ -638,21 +694,36 @@ const char* locale; char data[CP_MAX_PACKET]; int datalen; + char* clientVersion; + unsigned int features = MXIT_CP_FEATURES; locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE ); + /* Voice and Video supported */ + if (mxit_audio_enabled() && mxit_video_enabled()) + features |= (MXIT_CF_VOICE | MXIT_CF_VIDEO); + else if (mxit_audio_enabled()) + features |= MXIT_CF_VOICE; + + /* generate client version string (eg, P-2.7.10-Y-PURPLE) */ + clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM ); + /* convert the packet to a byte stream */ datalen = snprintf( data, sizeof( data ), "ms=%s%c%s%c%i%c%s%c" /* "ms"=password\1version\1maxreplyLen\1name\1 */ "%s%c%i%c%s%c%s%c" /* dateOfBirth\1gender\1location\1capabilities\1 */ - "%s%c%i%c%s%c%s", /* dc\1features\1dialingcode\1locale */ - session->encpwd, CP_FLD_TERM, MXIT_CP_VERSION, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, profile->nickname, CP_FLD_TERM, + "%s%c%i%c%s%c%s" /* dc\1features\1dialingcode\1locale */ + "%c%i%c%i", /* \1protocolVer\1lastRosterUpdate */ + session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, profile->nickname, CP_FLD_TERM, profile->birthday, CP_FLD_TERM, ( profile->male ) ? 1 : 0, CP_FLD_TERM, MXIT_DEFAULT_LOC, CP_FLD_TERM, MXIT_CP_CAP, CP_FLD_TERM, - session->distcode, CP_FLD_TERM, MXIT_CP_FEATURES, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale + session->distcode, CP_FLD_TERM, features, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale, + CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0 ); /* queue packet for transmission */ mxit_queue_packet( session, data, datalen, CP_CMD_REGISTER ); + + g_free( clientVersion ); } @@ -663,21 +734,32 @@ */ void mxit_send_login( struct MXitSession* session ) { - const char* splashId; - const char* locale; - char data[CP_MAX_PACKET]; - int datalen; + const char* splashId; + const char* locale; + char data[CP_MAX_PACKET]; + int datalen; + char* clientVersion; + unsigned int features = MXIT_CP_FEATURES; locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE ); + /* Voice and Video supported */ + if (mxit_audio_enabled() && mxit_video_enabled()) + features |= (MXIT_CF_VOICE | MXIT_CF_VIDEO); + else if (mxit_audio_enabled()) + features |= MXIT_CF_VOICE; + + /* generate client version string (eg, P-2.7.10-Y-PURPLE) */ + clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM ); + /* convert the packet to a byte stream */ datalen = snprintf( data, sizeof( data ), "ms=%s%c%s%c%i%c" /* "ms"=password\1version\1getContacts\1 */ "%s%c%s%c%i%c" /* capabilities\1dc\1features\1 */ "%s%c%s%c" /* dialingcode\1locale\1 */ "%i%c%i%c%i", /* maxReplyLen\1protocolVer\1lastRosterUpdate */ - session->encpwd, CP_FLD_TERM, MXIT_CP_VERSION, CP_FLD_TERM, 1, CP_FLD_TERM, - MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, MXIT_CP_FEATURES, CP_FLD_TERM, + session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, 1, CP_FLD_TERM, + MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, features, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0 ); @@ -689,6 +771,8 @@ /* queue packet for transmission */ mxit_queue_packet( session, data, datalen, CP_CMD_LOGIN ); + + g_free( clientVersion ); } @@ -732,7 +816,7 @@ * @param session The MXit session object * @param username Username who's profile is being requested (NULL = our own) * @param nr_attribs Number of attributes being requested - * @param attributes The names of the attributes + * @param attribute The names of the attributes */ void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] ) { @@ -742,7 +826,8 @@ datalen = snprintf( data, sizeof( data ), "ms=%s%c%i", /* "ms="mxitid\1nr_attributes */ - (username ? username : ""), CP_FLD_TERM, nr_attrib); + ( username ? username : "" ), CP_FLD_TERM, nr_attrib + ); /* add attributes */ for ( i = 0; i < nr_attrib; i++ ) @@ -790,6 +875,63 @@ /*------------------------------------------------------------------------ + * Send packet to request list of suggested friends. + * + * @param session The MXit session object + * @param max Maximum number of results to return + * @param nr_attribs Number of attributes being requested + * @param attribute The names of the attributes + */ +void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] ) +{ + char data[CP_MAX_PACKET]; + int datalen; + unsigned int i; + + /* convert the packet to a byte stream */ + datalen = snprintf( data, sizeof( data ), + "ms=%i%c%s%c%i%c%i", /* inputType \1 input \ 1 maxSuggestions \1 numAttributes \1 name0 ... \1 nameN */ + CP_SUGGEST_FRIENDS, CP_FLD_TERM, "", CP_FLD_TERM, max, CP_FLD_TERM, nr_attrib ); + + /* add attributes */ + for ( i = 0; i < nr_attrib; i++ ) + datalen += sprintf( data + datalen, "%c%s", CP_FLD_TERM, attribute[i] ); + + /* queue packet for transmission */ + mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS ); +} + + +/*------------------------------------------------------------------------ + * Send packet to perform a search for users. + * + * @param session The MXit session object + * @param max Maximum number of results to return + * @param text The search text + * @param nr_attribs Number of attributes being requested + * @param attribute The names of the attributes + */ +void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] ) +{ + char data[CP_MAX_PACKET]; + int datalen; + unsigned int i; + + /* convert the packet to a byte stream */ + datalen = snprintf( data, sizeof( data ), + "ms=%i%c%s%c%i%c%i", /* inputType \1 input \ 1 maxSuggestions \1 numAttributes \1 name0 ... \1 nameN */ + CP_SUGGEST_SEARCH, CP_FLD_TERM, text, CP_FLD_TERM, max, CP_FLD_TERM, nr_attrib ); + + /* add attributes */ + for ( i = 0; i < nr_attrib; i++ ) + datalen += sprintf( data + datalen, "%c%s", CP_FLD_TERM, attribute[i] ); + + /* queue packet for transmission */ + mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS ); +} + + +/*------------------------------------------------------------------------ * Send a presence update packet to the MXit server. * * @param session The MXit session object @@ -1039,7 +1181,6 @@ * @param nr_usernames Number of users being invited * @param usernames The usernames of the users being invited */ - void mxit_send_groupchat_invite( struct MXitSession* session, const char* roomid, int nr_usernames, const char* usernames[] ) { char data[CP_MAX_PACKET]; @@ -1271,7 +1412,7 @@ /* map chunk header over data buffer */ chunk = &data[datalen]; - size = mxit_chunk_create_get_avatar( chunk_data(chunk), mxitId, avatarId, MXIT_AVATAR_SIZE ); + size = mxit_chunk_create_get_avatar( chunk_data(chunk), mxitId, avatarId ); if ( size < 0 ) { purple_debug_error( MXIT_PLUGIN_ID, "Error creating get avatar chunk (%i)\n", size ); return; @@ -1322,6 +1463,10 @@ if ( records[1]->fcount >= 9 ) session->uid = g_strdup( records[1]->fields[8]->data ); + /* extract VoIP server (from protocol 6.2) */ + if ( records[1]->fcount >= 11 ) + g_strlcpy( session->voip_server, records[1]->fields[10]->data, sizeof( session->voip_server ) ); + /* display the current splash-screen */ if ( splash_popup_enabled( session ) ) splash_display( session ); @@ -1567,13 +1712,13 @@ */ static void mxit_parse_cmd_presence( struct MXitSession* session, struct record** records, int rcount ) { - struct record* rec; int i; purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_presence (%i recs)\n", rcount ); for ( i = 0; i < rcount; i++ ) { - rec = records[i]; + struct record* rec = records[i]; + int flags = 0; if ( rec->fcount < 6 ) { purple_debug_error( MXIT_PLUGIN_ID, "BAD PRESENCE RECORD! %i fields\n", rec->fcount ); @@ -1582,12 +1727,15 @@ /* * The format of the record is: - * contactAddressN\1presenceN\1moodN\1customMoodN\1statusMsgN\1avatarIdN + * contactAddressN \1 presenceN \1 moodN \1 customMoodN \1 statusMsgN \1 avatarIdN [ \1 flagsN ] */ mxit_strip_domain( rec->fields[0]->data ); /* contactAddress */ + if ( rec->fcount >= 7 ) /* flags field is included */ + flags = atoi( rec->fields[6]->data ); + mxit_update_buddy_presence( session, rec->fields[0]->data, atoi( rec->fields[1]->data ), atoi( rec->fields[2]->data ), - rec->fields[3]->data, rec->fields[4]->data ); + rec->fields[3]->data, rec->fields[4]->data, flags ); mxit_update_buddy_avatar( session, rec->fields[0]->data, rec->fields[5]->data ); } } @@ -1908,7 +2056,7 @@ { /* ignore ping/poll packets */ if ( ( packet->cmd != CP_CMD_PING ) && ( packet->cmd != CP_CMD_POLL ) ) - session->last_rx = time( NULL ); + session->last_rx = mxit_now_milli(); /* * when we pass the packet records to the next level for parsing diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/protocol.h --- a/libpurple/protocols/mxit/protocol.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/protocol.h Mon Apr 25 20:13:05 2011 +0000 @@ -75,6 +75,8 @@ #define MXIT_CF_NO_AVATARS 0x200000 #define MXIT_CF_GAMING 0x400000 #define MXIT_CF_GAMING_UPDATE 0x800000 +#define MXIT_CF_VOICE 0x1000000 +#define MXIT_CF_VIDEO 0x2000000 /* Client features supported by this implementation */ #define MXIT_CP_FEATURES ( MXIT_CF_FILE_TRANSFER | MXIT_CF_FILE_ACCESS | MXIT_CF_AUDIO | MXIT_CF_MARKUP | MXIT_CF_EXT_MARKUP | MXIT_CF_NO_GATEWAYS | MXIT_CF_IMAGES | MXIT_CF_COMMANDS | MXIT_CF_VIBES | MXIT_CF_MIDP2 ) @@ -82,14 +84,13 @@ #define MXIT_PING_INTERVAL ( 5 * 60 ) /* ping the server after X seconds of being idle (5 minutes) */ #define MXIT_ACK_TIMEOUT ( 30 ) /* timeout after waiting X seconds for an ack from the server (30 seconds) */ +#define MXIT_TX_DELAY ( 100 ) /* delay between sending consecutive packets (100 ms) */ /* MXit client version */ -#define MXIT_CP_DISTCODE "P" /* client distribution code (magic, do not touch!) */ -#define MXIT_CP_RELEASE "5.9.0" /* client version */ +#define MXIT_CP_DISTCODE 'P' /* client distribution code (magic, do not touch!) */ #define MXIT_CP_ARCH "Y" /* client architecture series (Y not for Yoda but for PC-client) */ #define MXIT_CLIENT_ID "LP" /* client ID as specified by MXit */ #define MXIT_CP_PLATFORM "PURPLE" /* client platform */ -#define MXIT_CP_VERSION MXIT_CP_DISTCODE"-"MXIT_CP_RELEASE"-"MXIT_CP_ARCH"-"MXIT_CP_PLATFORM #define MXIT_CP_PROTO_VESION 60 /* client protocol version */ /* set operating system name */ @@ -107,7 +108,7 @@ #define MXIT_CP_CAP "utf8=true;cid="MXIT_CLIENT_ID /* Client settings */ -#define MAX_QUEUE_SIZE ( 1 << 4 ) /* tx queue size (16 packets) */ +#define MAX_QUEUE_SIZE ( 1 << 5 ) /* tx queue size (32 packets) */ #define MXIT_POPUP_WIN_NAME "MXit Notification" /* popup window name */ #define MXIT_MAX_ATTRIBS 10 /* maximum profile attributes supported */ #define MXIT_DEFAULT_LOCALE "en" /* default locale setting */ @@ -125,6 +126,7 @@ #define CP_CMD_TX_MSG 0x000A /* (10) send new message */ #define CP_CMD_REGISTER 0x000B /* (11) register */ //#define CP_CMD_PROFILE_SET 0x000C /* (12) set profile (DEPRECATED see CP_CMD_EXTPROFILE_SET) */ +#define CP_CMD_SUGGESTCONTACTS 0x000D /* (13) suggest contacts */ #define CP_CMD_POLL 0x0011 /* (17) poll the HTTP server for an update */ //#define CP_CMD_PROFILE_GET 0x001A /* (26) get profile (DEPRECATED see CP_CMD_EXTPROFILE_GET) */ #define CP_CMD_MEDIA 0x001B /* (27) get multimedia message */ @@ -202,6 +204,12 @@ /* profile flags */ #define CP_PROF_DOBLOCKED 0x40 /* date-of-birth cannot be changed */ +/* suggestion types */ +#define CP_SUGGEST_ADDRESSBOOK 0 /* address book search */ +#define CP_SUGGEST_FRIENDS 1 /* suggested friends */ +#define CP_SUGGEST_SEARCH 2 /* free-text search */ +#define CP_SUGGEST_MXITID 3 /* MXitId search */ + /* define this to enable protocol debugging (very verbose logging) */ #define DEBUG_PROTOCOL @@ -277,7 +285,8 @@ gboolean find_active_chat( const GList* chats, const char* who ); void mxit_cb_rx( gpointer data, gint source, PurpleInputCondition cond ); -gboolean mxit_manage_queue( gpointer user_data ); +gboolean mxit_manage_queue_slow( gpointer user_data ); +gboolean mxit_manage_queue_fast( gpointer user_data ); gboolean mxit_manage_polling( gpointer user_data ); void mxit_send_register( struct MXitSession* session ); @@ -293,6 +302,9 @@ void mxit_send_extprofile_update( struct MXitSession* session, const char* password, unsigned int nr_attrib, const char* attributes ); void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] ); +void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] ); +void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] ); + void mxit_send_invite( struct MXitSession* session, const char* username, const char* alias, const char* groupname ); void mxit_send_remove( struct MXitSession* session, const char* username ); void mxit_send_allow_sub( struct MXitSession* session, const char* username, const char* alias ); @@ -314,6 +326,7 @@ int mxit_parse_packet( struct MXitSession* session ); void dump_bytes( struct MXitSession* session, const char* buf, int len ); void mxit_close_connection( struct MXitSession* session ); +gint64 mxit_now_milli( void ); #endif /* _MXIT_PROTO_H_ */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/roster.c --- a/libpurple/protocols/mxit/roster.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/roster.c Mon Apr 25 20:13:05 2011 +0000 @@ -443,8 +443,9 @@ * @param mood The new mood for the contact * @param customMood The custom mood identifier * @param statusMsg This is the contact's status message + * @param flags The contact's presence flags. */ -void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg ) +void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg, int flags ) { PurpleBuddy* buddy = NULL; struct contact* contact = NULL; @@ -470,6 +471,7 @@ contact->presence = presence; contact->mood = mood; + contact->capabilities = flags; /* validate mood */ if (( contact->mood < MXIT_MOOD_NONE ) || ( contact->mood > MXIT_MOOD_STRESSED )) diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/roster.h --- a/libpurple/protocols/mxit/roster.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/mxit/roster.h Mon Apr 25 20:13:05 2011 +0000 @@ -79,6 +79,11 @@ #define MXIT_CFLAG_FOCUS_SEND_BLANK 0x20000 +/* MXit presence flags */ +#define MXIT_PFLAG_VOICE 0x1 +#define MXIT_PFLAG_VIDEO 0x2 + + /* Subscription types */ #define MXIT_SUBTYPE_BOTH 'B' #define MXIT_SUBTYPE_PENDING 'P' @@ -108,6 +113,7 @@ short mood; /* contact current mood */ int flags; /* contact flags */ short presence; /* presence state */ + int capabilities; /* contact capabilities */ short subtype; /* subscription type */ char* msg; /* invite/rejection message */ @@ -129,7 +135,7 @@ /* MXit Protocol callbacks */ void mxit_update_contact( struct MXitSession* session, struct contact* contact ); -void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg ); +void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg, int flags ); void mxit_update_buddy_avatar( struct MXitSession* session, const char* username, const char* avatarId ); void mxit_new_subscription( struct MXitSession* session, struct contact* contact ); void mxit_update_blist( struct MXitSession* session ); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/voicevideo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/mxit/voicevideo.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,154 @@ +/* + * MXit Protocol libPurple Plugin + * + * -- voice & video -- + * + * Andrew Victor + * + * (C) Copyright 2010 MXit Lifestyle (Pty) Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "purple.h" +#include "mxit.h" +#include "roster.h" +#include "voicevideo.h" + +#if defined(USE_VV) && defined(MXIT_DEV_VV) + +#warning "MXit VV support enabled." + +/*------------------------------------------------------------------------ + * Does this client support Voice? + */ +gboolean mxit_audio_enabled(void) +{ + PurpleMediaManager *manager = purple_media_manager_get(); + PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager); + + return (caps & PURPLE_MEDIA_CAPS_AUDIO); +} + +/*------------------------------------------------------------------------ + * Does this client support Voice and Video? + */ +gboolean mxit_video_enabled(void) +{ + PurpleMediaManager *manager = purple_media_manager_get(); + PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager); + + return (caps & PURPLE_MEDIA_CAPS_VIDEO); +} + +/*------------------------------------------------------------------------ + * Return the list of media capabilities this contact supports. + * + * @param account The MXit account object + * @param who The username of the contact. + * @return The media capabilities supported + */ +PurpleMediaCaps mxit_media_caps(PurpleAccount *account, const char *who) +{ + struct MXitSession* session = purple_account_get_connection(account)->proto_data; + PurpleBuddy* buddy; + struct contact* contact; + PurpleMediaCaps capa = PURPLE_MEDIA_CAPS_NONE; + + purple_debug_info(MXIT_PLUGIN_ID, "mxit_media_caps: buddy '%s'\n", who); + + /* We need to have a voice/video server */ + if (strlen(session->voip_server) == 0) + return PURPLE_MEDIA_CAPS_NONE; + + /* find the buddy information for this contact (reference: "libpurple/blist.h") */ + buddy = purple_find_buddy(account, who); + if (!buddy) { + purple_debug_warning(MXIT_PLUGIN_ID, "mxit_media_caps: unable to find the buddy '%s'\n", who); + return PURPLE_MEDIA_CAPS_NONE; + } + + contact = purple_buddy_get_protocol_data(buddy); + if (!contact) + return PURPLE_MEDIA_CAPS_NONE; + + /* can only communicate with MXit users */ + if (contact->type != MXIT_TYPE_MXIT) + return PURPLE_MEDIA_CAPS_NONE; + + /* and only with contacts in the 'Both' subscription state */ + if (contact->subtype != MXIT_SUBTYPE_BOTH) + return PURPLE_MEDIA_CAPS_NONE; + + /* and only when they're online */ + if (contact->presence == MXIT_PRESENCE_OFFLINE) + return MXIT_PRESENCE_OFFLINE; + + /* they support voice-only */ + if (contact->capabilities & MXIT_PFLAG_VOICE) + capa |= PURPLE_MEDIA_CAPS_AUDIO; + + /* they support voice-and-video */ + if (contact->capabilities & MXIT_PFLAG_VIDEO) + capa |= (PURPLE_MEDIA_CAPS_AUDIO | PURPLE_MEDIA_CAPS_VIDEO | PURPLE_MEDIA_CAPS_AUDIO_VIDEO); + + return capa; +} + + +/*------------------------------------------------------------------------ + * Initiate a voice/video session with a contact. + * + * @param account The MXit account object + * @param who The username of the contact. + * @param type The type of media session to initiate + * @return TRUE if session was initiated + */ +gboolean mxit_media_initiate(PurpleAccount *account, const char *who, PurpleMediaSessionType type) +{ + purple_debug_info(MXIT_PLUGIN_ID, "mxit_media_initiate: buddy '%s'\n", who); + + return FALSE; +} + +#else + +/* + * Voice and Video not supported. + */ + +gboolean mxit_audio_enabled(void) +{ + return FALSE; +} + +gboolean mxit_video_enabled(void) +{ + return FALSE; +} + +PurpleMediaCaps mxit_media_caps(PurpleAccount *account, const char *who) +{ + return PURPLE_MEDIA_CAPS_NONE; +} + +gboolean mxit_media_initiate(PurpleAccount *account, const char *who, PurpleMediaSessionType type) +{ + return FALSE; +} + +#endif + diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/mxit/voicevideo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/mxit/voicevideo.h Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,41 @@ +/* + * MXit Protocol libPurple Plugin + * + * -- voice & video -- + * + * Andrew Victor + * + * (C) Copyright 2010 MXit Lifestyle (Pty) Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef _MXIT_VOICEVICEO_H_ +#define _MXIT_VOICEVIDEO_H_ + +#include "media.h" + + +#undef MXIT_DEV_VV + + +gboolean mxit_audio_enabled(void); +gboolean mxit_video_enabled(void); +PurpleMediaCaps mxit_media_caps(PurpleAccount* account, const char* who); +gboolean mxit_media_initiate(PurpleAccount* account, const char* who, PurpleMediaSessionType type); + + +#endif /* _MXIT_VOICEVIDEO_H_ */ diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/myspace/myspace.c Mon Apr 25 20:13:05 2011 +0000 @@ -385,21 +385,22 @@ g_return_val_if_fail(buddy != NULL, NULL); - user = msim_get_user_from_buddy(buddy, TRUE); - account = purple_buddy_get_account(buddy); gc = purple_account_get_connection(account); session = (MsimSession *)gc->proto_data; display_name = headline = NULL; - /* Retrieve display name and/or headline, depending on user preference. */ - if (purple_account_get_bool(session->account, "show_headline", TRUE)) { - headline = user->headline; - } - - if (purple_account_get_bool(session->account, "show_display_name", FALSE)) { - display_name = user->display_name; + user = msim_get_user_from_buddy(buddy, FALSE); + if (user != NULL) { + /* Retrieve display name and/or headline, depending on user preference. */ + if (purple_account_get_bool(account, "show_headline", TRUE)) { + headline = user->headline; + } + + if (purple_account_get_bool(account, "show_display_name", FALSE)) { + display_name = user->display_name; + } } /* Return appropriate combination of display name and/or headline, or neither. */ @@ -3096,7 +3097,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; /** diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/novell/novell.c --- a/libpurple/protocols/novell/novell.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/novell/novell.c Mon Apr 25 20:13:05 2011 +0000 @@ -3531,7 +3531,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = { diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/null/nullprpl.c --- a/libpurple/protocols/null/nullprpl.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/null/nullprpl.c Mon Apr 25 20:13:05 2011 +0000 @@ -1120,9 +1120,11 @@ NULL, /* get_account_text_table */ NULL, /* initiate_media */ NULL, /* get_media_caps */ + NULL, /* get_moods */ NULL, /* set_public_alias */ NULL, /* get_public_alias */ - NULL /* get_moods */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static void nullprpl_init(PurplePlugin *plugin) diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/authorization.c --- a/libpurple/protocols/oscar/authorization.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/authorization.c Mon Apr 25 20:13:05 2011 +0000 @@ -25,20 +25,19 @@ #include "oscar.h" #include "request.h" -static void -oscar_auth_request(struct name_data *data, char *msg) +/* When you ask other people for authorization */ +void +oscar_auth_sendrequest(PurpleConnection *gc, const char *bname, const char *msg) { - PurpleConnection *gc; OscarData *od; PurpleAccount *account; PurpleBuddy *buddy; PurpleGroup *group; - const char *bname, *gname; + const char *gname; - gc = data->gc; od = purple_connection_get_protocol_data(gc); account = purple_connection_get_account(gc); - buddy = purple_find_buddy(account, data->name); + buddy = purple_find_buddy(account, bname); if (buddy != NULL) group = purple_buddy_get_group(buddy); else @@ -46,11 +45,10 @@ if (group != NULL) { - bname = purple_buddy_get_name(buddy); gname = purple_group_get_name(group); purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", bname, gname); - aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); + aim_ssi_sendauthrequest(od, bname, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) { aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE); @@ -66,8 +64,6 @@ } } } - - oscar_free_name_data(data); } static void @@ -105,24 +101,6 @@ data); } -/* When you ask other people for authorization */ -void -oscar_auth_sendrequest(PurpleConnection *gc, const char *name) -{ - struct name_data *data; - - data = g_new0(struct name_data, 1); - data->gc = gc; - data->name = g_strdup(name); - - purple_request_input(data->gc, NULL, _("Authorization Request Message:"), - NULL, _("Please authorize me!"), TRUE, FALSE, NULL, - _("_OK"), G_CALLBACK(oscar_auth_request), - _("_Cancel"), G_CALLBACK(oscar_free_name_data), - purple_connection_get_account(gc), name, NULL, - data); -} - void oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored) { @@ -133,7 +111,7 @@ buddy = (PurpleBuddy *) node; gc = purple_account_get_connection(purple_buddy_get_account(buddy)); - oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy)); + oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy), NULL); } /* When other people ask you for authorization */ @@ -150,4 +128,4 @@ purple_account_request_authorization(account, data->name, NULL, data->nick, reason, purple_find_buddy(account, data->name) != NULL, oscar_auth_grant, oscar_auth_dontgrant_msgprompt, data); -} \ No newline at end of file +} diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/family_feedbag.c --- a/libpurple/protocols/oscar/family_feedbag.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/family_feedbag.c Mon Apr 25 20:13:05 2011 +0000 @@ -824,7 +824,7 @@ return -EINVAL; if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL) - aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, list_type, NULL); + aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL); aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL); return aim_ssi_sync(od); @@ -1682,7 +1682,7 @@ * granted, denied, or dropped. * */ -int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg) +int aim_ssi_sendauthrequest(OscarData *od, const char *bn, const char *msg) { FlapConnection *conn; ByteStream bs; @@ -1759,7 +1759,7 @@ * if reply=0x01 then grant * */ -int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg) +int aim_ssi_sendauthreply(OscarData *od, const char *bn, guint8 reply, const char *msg) { FlapConnection *conn; ByteStream bs; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/flap_connection.c --- a/libpurple/protocols/oscar/flap_connection.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Mon Apr 25 20:13:05 2011 +0000 @@ -208,7 +208,7 @@ * @param data The optional bytestream that makes up the data portion * of this SNAC. For empty SNACs this should be NULL. * @param high_priority If TRUE, the SNAC will be queued normally if - * needed. If FALSE, it wil be queued separately, to be sent + * needed. If FALSE, it will be queued separately, to be sent * only if all high priority SNACs have been sent. */ void diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/libaim.c --- a/libpurple/protocols/oscar/libaim.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/libaim.c Mon Apr 25 20:13:05 2011 +0000 @@ -29,7 +29,7 @@ static PurplePluginProtocolInfo prpl_info = { - OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE, + OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE, NULL, /* user_splits */ NULL, /* protocol_options */ {"gif,jpeg,bmp,ico", 0, 0, 100, 100, 7168, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ @@ -50,7 +50,7 @@ oscar_set_status, /* set_status */ oscar_set_idle, /* set_idle */ oscar_change_passwd, /* change_passwd */ - oscar_add_buddy, /* add_buddy */ + NULL, /* add_buddy */ NULL, /* add_buddies */ oscar_remove_buddy, /* remove_buddy */ NULL, /* remove_buddies */ @@ -100,7 +100,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + oscar_add_buddy, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/libicq.c --- a/libpurple/protocols/oscar/libicq.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/libicq.c Mon Apr 25 20:13:05 2011 +0000 @@ -38,7 +38,7 @@ static PurplePluginProtocolInfo prpl_info = { - OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE, + OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE, NULL, /* user_splits */ NULL, /* protocol_options */ {"gif,jpeg,bmp,ico", 0, 0, 100, 100, 7168, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ @@ -59,7 +59,7 @@ oscar_set_status, /* set_status */ oscar_set_idle, /* set_idle */ oscar_change_passwd, /* change_passwd */ - oscar_add_buddy, /* add_buddy */ + NULL, /* add_buddy */ NULL, /* add_buddies */ oscar_remove_buddy, /* remove_buddy */ NULL, /* remove_buddies */ @@ -110,7 +110,9 @@ NULL, /* can_do_media */ oscar_get_purple_moods, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + oscar_add_buddy, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/oscar.c Mon Apr 25 20:13:05 2011 +0000 @@ -2828,6 +2828,52 @@ return 1; } +static void oscar_format_username(PurpleConnection *gc, const char *new_display_name) +{ + OscarData *od; + const char *old_display_name, *username; + char *tmp, *at_sign; + + old_display_name = purple_connection_get_display_name(gc); + if (old_display_name && strchr(old_display_name, '@')) { + purple_debug_info("oscar", "Cowardly refusing to attempt to format " + "screen name because the current formatting according to " + "the server (%s) appears to be an email address\n", + old_display_name); + return; + } + + username = purple_account_get_username(purple_connection_get_account(gc)); + if (oscar_util_name_compare(username, new_display_name)) { + purple_notify_error(gc, NULL, _("The new formatting is invalid."), + _("Username formatting can change only capitalization and whitespace.")); + return; + } + + tmp = g_strdup(new_display_name); + + /* + * If our local username is an email address then strip off the domain. + * This allows formatting to work if the user entered their username as + * 'something@aim.com' or possibly other AOL-owned domains. + */ + at_sign = strchr(tmp, '@'); + if (at_sign) + at_sign[0] = '\0'; + + od = purple_connection_get_protocol_data(gc); + if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) { + /* We don't have a connection to an "admin" server. Make one. */ + od->setnick = TRUE; + g_free(od->newformatting); + od->newformatting = tmp; + aim_srv_requestnew(od, SNAC_FAMILY_ADMIN); + } else { + aim_admin_setnick(od, flap_connection_getbytype(od, SNAC_FAMILY_ADMIN), tmp); + g_free(tmp); + } +} + static int purple_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc; PurpleAccount *account; @@ -2860,12 +2906,13 @@ serv_set_info(gc, purple_account_get_user_info(account)); username = purple_account_get_username(account); - if (!od->icq && strcmp(username, purple_connection_get_display_name(gc)) != 0) + if (!od->icq && strcmp(username, purple_connection_get_display_name(gc)) != 0) { /* * Format the username for AIM accounts if it's different * than what's currently set. */ oscar_format_username(gc, username); + } /* Set our available message based on the current status */ status = purple_account_get_active_status(account); @@ -3093,12 +3140,12 @@ oscar_keepalive(PurpleConnection *gc) { OscarData *od; - FlapConnection *conn; + GSList *l; od = purple_connection_get_protocol_data(gc); - conn = flap_connection_getbytype(od, SNAC_FAMILY_LOCATE); - if (conn != NULL) - flap_connection_send_keepalive(od, conn); + for (l = od->oscar_connections; l; l = l->next) { + flap_connection_send_keepalive(od, l->data); + } } unsigned int @@ -3638,7 +3685,8 @@ } void -oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { +oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *msg) +{ OscarData *od; PurpleAccount *account; const char *bname, *gname; @@ -3678,7 +3726,7 @@ aim_ssi_itemlist_findparentname(od->ssi.local, bname), bname)) { /* Not authorized -- Re-request authorization */ - oscar_auth_sendrequest(gc, bname); + oscar_auth_sendrequest(gc, bname, msg); } } @@ -3953,9 +4001,12 @@ /*** Begin code for adding from server list to local list ***/ for (curitem=od->ssi.local; curitem; curitem=curitem->next) { - if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL)) + if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL)) { /* Got node with invalid UTF-8 in the name. Skip it. */ - break; + purple_debug_warning("oscar", "ssi: server list contains item of " + "type 0x%04hhx with a non-utf8 name\n", curitem->type); + continue; + } switch (curitem->type) { case AIM_SSI_TYPE_BUDDY: { /* Buddy */ @@ -4004,17 +4055,10 @@ } break; case AIM_SSI_TYPE_GROUP: { /* Group */ - char *gname; - char *gname_utf8; - - gname = curitem->name; - gname_utf8 = oscar_utf8_try_convert(account, od, gname); - - if (gname_utf8 != NULL && purple_find_group(gname_utf8) == NULL) { - g = purple_group_new(gname_utf8); + if (curitem->name != NULL && purple_find_group(curitem->name) == NULL) { + g = purple_group_new(curitem->name); purple_blist_add_group(g, NULL); } - g_free(gname_utf8); } break; case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */ @@ -4132,7 +4176,7 @@ case 0x000e: { /* buddy requires authorization */ if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name)) - oscar_auth_sendrequest(gc, retval->name); + oscar_auth_sendrequest(gc, retval->name, NULL); } break; default: { /* La la la */ @@ -5017,16 +5061,22 @@ { PurpleBuddy *buddy; PurpleConnection *gc; + OscarData *od; PurpleAccount *account; + const char *bname; g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); buddy = (PurpleBuddy *)node; - gc = purple_account_get_connection(buddy->account); - account = purple_connection_get_account(gc); - purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", purple_buddy_get_name(buddy), account->username); - - icq_im_xstatus_request(gc->proto_data, purple_buddy_get_name(buddy)); + bname = purple_buddy_get_name(buddy); + + account = purple_buddy_get_account(buddy); + gc = purple_account_get_connection(account); + od = purple_connection_get_protocol_data(gc); + + purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", bname, purple_account_get_username(account)); + + icq_im_xstatus_request(od, bname); } static void @@ -5196,23 +5246,6 @@ gc); } -void oscar_format_username(PurpleConnection *gc, const char *nick) { - OscarData *od = purple_connection_get_protocol_data(gc); - if (!oscar_util_name_compare(purple_account_get_username(purple_connection_get_account(gc)), nick)) { - if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) { - od->setnick = TRUE; - g_free(od->newformatting); - od->newformatting = g_strdup(nick); - aim_srv_requestnew(od, SNAC_FAMILY_ADMIN); - } else { - aim_admin_setnick(od, flap_connection_getbytype(od, SNAC_FAMILY_ADMIN), nick); - } - } else { - purple_notify_error(gc, NULL, _("The new formatting is invalid."), - _("Username formatting can change only capitalization and whitespace.")); - } -} - static void oscar_confirm_account(PurplePluginAction *action) { PurpleConnection *gc; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/oscar.h Mon Apr 25 20:13:05 2011 +0000 @@ -912,8 +912,8 @@ /* 0x0007 */ int aim_ssi_enable(OscarData *od); /* 0x0011 */ int aim_ssi_modbegin(OscarData *od); /* 0x0012 */ int aim_ssi_modend(OscarData *od); -/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg); -/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg); +/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, const char *bn, const char *msg); +/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, const char *bn, guint8 reply, const char *msg); /* Client functions for retrieving SSI data */ struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid); @@ -1311,7 +1311,7 @@ void oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo); /* authorization.c - OSCAR authorization requests */ -void oscar_auth_sendrequest(PurpleConnection *gc, const char *name); +void oscar_auth_sendrequest(PurpleConnection *gc, const char *name, const char *msg); void oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored); void oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/oscar/oscarcommon.h --- a/libpurple/protocols/oscar/oscarcommon.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Mon Apr 25 20:13:05 2011 +0000 @@ -79,7 +79,7 @@ void oscar_set_status(PurpleAccount *account, PurpleStatus *status); void oscar_set_idle(PurpleConnection *gc, int time); void oscar_change_passwd(PurpleConnection *gc, const char *old, const char *new); -void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); +void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *msg); void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); void oscar_add_permit(PurpleConnection *gc, const char *who); void oscar_add_deny(PurpleConnection *gc, const char *who); @@ -102,6 +102,5 @@ void oscar_send_file(PurpleConnection *gc, const char *who, const char *file); PurpleXfer *oscar_new_xfer(PurpleConnection *gc, const char *who); gboolean oscar_offline_message(const PurpleBuddy *buddy); -void oscar_format_username(PurpleConnection *gc, const char *nick); GList *oscar_actions(PurplePlugin *plugin, gpointer context); void oscar_init(PurplePlugin *plugin, gboolean is_icq); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/ChangeLog --- a/libpurple/protocols/qq/ChangeLog Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/ChangeLog Mon Apr 25 20:13:05 2011 +0000 @@ -1,3 +1,12 @@ +2010.01.23 - flos + * added an option to force incoming message in chat room to use a default font instead of the font in message itself + +2010.01.18 - flos + * added type 'UPDCLS' and 'UID' for implementing business logic layer + +2010.01.13 - ccpaging + * qq2009-1 patch from ccpaging + 2009.04.23 - flos * Fixed a bug of updating buddy who is not in user's buddy list diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Mon Apr 25 20:13:05 2011 +0000 @@ -26,6 +26,7 @@ #include "debug.h" #include "notify.h" #include "request.h" +#include "connection.h" #include "utils.h" #include "packet_parse.h" @@ -221,8 +222,8 @@ g_strfreev(segments); } -void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, - guint32 update_class, int action) +void qq_request_buddy_info(PurpleConnection *gc, UID uid, + UPDCLS update_class, int action) { gchar raw_data[16] = {0}; @@ -620,7 +621,7 @@ PurpleBuddy *buddy = NULL; qq_data *qd = NULL; qq_buddy_data *bd = NULL; - guint32 uid; + UID uid; gchar *who; gchar *alias_utf8; @@ -741,7 +742,7 @@ return; } -void qq_request_get_level(PurpleConnection *gc, guint32 uid) +void qq_request_get_level(PurpleConnection *gc, UID uid) { qq_data *qd = (qq_data *) gc->proto_data; guint8 buf[16] = {0}; @@ -756,7 +757,7 @@ qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); } -void qq_request_get_level_2007(PurpleConnection *gc, guint32 uid) +void qq_request_get_level_2007(PurpleConnection *gc, UID uid) { guint8 buf[16] = {0}; gint bytes = 0; @@ -767,7 +768,7 @@ qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); } -void qq_request_get_buddies_level(PurpleConnection *gc, guint32 update_class) +void qq_request_get_buddies_level(PurpleConnection *gc, UPDCLS update_class) { qq_data *qd = (qq_data *) gc->proto_data; PurpleBuddy *buddy; @@ -797,7 +798,8 @@ static void process_level(PurpleConnection *gc, guint8 *data, gint data_len) { gint bytes = 0; - guint32 uid, onlineTime; + UID uid; + guint32 onlineTime; guint16 level, timeRemainder; qq_buddy_data *bd; @@ -829,7 +831,8 @@ static void process_level_2007(PurpleConnection *gc, guint8 *data, gint data_len) { gint bytes; - guint32 uid, onlineTime; + UID uid; + guint32 onlineTime; guint16 level, timeRemainder; qq_buddy_data *bd; guint16 str_len; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_info.h --- a/libpurple/protocols/qq/buddy_info.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Mon Apr 25 20:13:05 2011 +0000 @@ -78,15 +78,14 @@ gchar *qq_get_icon_path(gchar *icon_name); void qq_change_icon_cb(PurpleConnection *gc, const char *filepath); -void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, - guint32 update_class, int action); +void qq_request_buddy_info(PurpleConnection *gc, UID uid, UPDCLS update_class, int action); void qq_set_custom_icon(PurpleConnection *gc, PurpleStoredImage *img); void qq_process_change_info(PurpleConnection *gc, guint8 *data, gint data_len); void qq_process_get_buddy_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc); -void qq_request_get_level(PurpleConnection *gc, guint32 uid); -void qq_request_get_level_2007(PurpleConnection *gc, guint32 uid); -void qq_request_get_buddies_level(PurpleConnection *gc, guint32 update_class); +void qq_request_get_level(PurpleConnection *gc, UID uid); +void qq_request_get_level_2007(PurpleConnection *gc, UID uid); +void qq_request_get_buddies_level(PurpleConnection *gc, UPDCLS update_class); void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); void qq_update_buddy_icon(PurpleAccount *account, const gchar *who, gint face); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Mon Apr 25 20:13:05 2011 +0000 @@ -53,7 +53,7 @@ } qq_buddy_online; /* get a list of online_buddies */ -void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, guint32 update_class) +void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, UPDCLS update_class) { guint8 *raw_data; gint bytes = 0; @@ -77,7 +77,7 @@ /* position starts with 0x0000, * server may return a position tag if list is too long for one packet */ -void qq_request_get_buddies(PurpleConnection *gc, guint16 position, guint32 update_class) +void qq_request_get_buddies(PurpleConnection *gc, guint16 position, UPDCLS update_class) { qq_data *qd; guint8 raw_data[16] = {0}; @@ -101,7 +101,7 @@ } /* get all list, buddies & Quns with groupsid support */ -void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, guint32 update_class) +void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, UPDCLS update_class) { guint8 raw_data[16] = {0}; gint bytes = 0; @@ -362,7 +362,7 @@ gint bytes; guint8 sub_cmd, reply_code; guint32 unknown, position; - guint32 uid; + UID uid; guint8 type; qq_room_data *rmd; @@ -455,7 +455,7 @@ } /* send a packet to change my online status */ -void qq_request_change_status(PurpleConnection *gc, guint32 update_class) +void qq_request_change_status(PurpleConnection *gc, UPDCLS update_class) { qq_data *qd; guint8 raw_data[16] = {0}; @@ -525,7 +525,7 @@ { qq_data *qd; gint bytes; - guint32 my_uid; + UID my_uid; gchar *who; PurpleBuddy *buddy; qq_buddy_data *bd; @@ -583,7 +583,7 @@ } /*TODO: maybe this should be qq_update_buddy_status() ?*/ -void qq_update_buddy_status(PurpleConnection *gc, guint32 uid, guint8 status, guint8 flag) +void qq_update_buddy_status(PurpleConnection *gc, UID uid, guint8 status, guint8 flag) { gchar *who; const gchar *status_id; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_list.h --- a/libpurple/protocols/qq/buddy_list.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_list.h Mon Apr 25 20:13:05 2011 +0000 @@ -30,7 +30,7 @@ #include "qq.h" typedef struct _qq_buddy_status { - guint32 uid; + UID uid; guint8 unknown1; struct in_addr ip; guint16 port; @@ -40,20 +40,20 @@ guint8 unknown_key[QQ_KEY_LENGTH]; } qq_buddy_status; -void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, guint32 update_class); +void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, UPDCLS update_class); guint8 qq_process_get_buddies_online(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_request_get_buddies(PurpleConnection *gc, guint16 position, guint32 update_class); +void qq_request_get_buddies(PurpleConnection *gc, guint16 position, UPDCLS update_class); guint16 qq_process_get_buddies(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, guint32 update_class); +void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, UPDCLS update_class); guint32 qq_process_get_buddies_and_rooms(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_request_change_status(PurpleConnection *gc, guint32 update_class); +void qq_request_change_status(PurpleConnection *gc, UPDCLS update_class); void qq_process_change_status(guint8 *data, gint data_len, PurpleConnection *gc); void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc); void qq_update_buddyies_status(PurpleConnection *gc); -void qq_update_buddy_status(PurpleConnection *gc, guint32 uid, guint8 status, guint8 flag); +void qq_update_buddy_status(PurpleConnection *gc, UID uid, guint8 status, guint8 flag); void qq_buddy_data_free_all(PurpleConnection *gc); #endif diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_memo.c --- a/libpurple/protocols/qq/buddy_memo.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_memo.c Mon Apr 25 20:13:05 2011 +0000 @@ -83,7 +83,7 @@ typedef struct _modify_memo_request { PurpleConnection *gc; - guint32 bd_uid; + UID bd_uid; gchar **segments; } modify_memo_request; @@ -107,7 +107,7 @@ purple_debug_info("QQ", "memo freed\n"); } -static void update_buddy_memo(PurpleConnection *gc, guint32 bd_uid, gchar *alias) +static void update_buddy_memo(PurpleConnection *gc, UID bd_uid, gchar *alias) { PurpleAccount *account; PurpleBuddy *buddy; @@ -127,7 +127,7 @@ purple_blist_alias_buddy(buddy, (const char*)alias); } -static void request_change_memo(PurpleConnection *gc, guint32 bd_uid, gchar **segments) +static void request_change_memo(PurpleConnection *gc, UID bd_uid, gchar **segments) { gint bytes; /* Attention, length of each segment must be guint8(0~255), @@ -170,7 +170,7 @@ static void memo_modify_ok_cb(modify_memo_request *memo_request, PurpleRequestFields *fields) { PurpleConnection *gc; - guint32 bd_uid; + UID bd_uid; gchar **segments; const gchar *utf8_str; gchar *value = NULL; @@ -187,7 +187,7 @@ utf8_str = purple_request_fields_get_string(fields, memo_id[index]); /* update alias */ if (QQ_MEMO_ALIAS == index) { - update_buddy_memo(gc, bd_uid, segments[QQ_MEMO_ALIAS]); + update_buddy_memo(gc, (UID)bd_uid, segments[QQ_MEMO_ALIAS]); } if (NULL == utf8_str) { value = g_strdup(""); @@ -213,7 +213,7 @@ } /* memo modify dialogue */ -static void memo_modify_dialogue(PurpleConnection *gc, guint32 bd_uid, gchar **segments, guint32 action) +static void memo_modify_dialogue(PurpleConnection *gc, UID bd_uid, gchar **segments, guint32 action) { modify_memo_request *memo_request; PurpleRequestField *field; @@ -272,7 +272,7 @@ } } -static void qq_create_buddy_memo(PurpleConnection *gc, guint32 bd_uid, guint32 action) +static void qq_create_buddy_memo(PurpleConnection *gc, UID bd_uid, guint32 action) { gchar **segments; gint index; @@ -285,9 +285,11 @@ memo_modify_dialogue(gc, bd_uid, segments, action); } -/* process reply to get_memo packet */ +/* process reply to get_memo packet + * here, update_class will be regarded as buddy's uid. because some + * memo packages returned without uid, which will make us confused */ void qq_process_get_buddy_memo(PurpleConnection *gc, guint8* data, gint data_len, - guint32 update_class, guint32 action) + UPDCLS update_class, guint32 action) { gchar **segments; gint bytes; @@ -314,7 +316,9 @@ if (1 == data_len) { /* only one byte */ purple_debug_info("QQ", "memo packet contains no buddy uid and memo...\n"); if (QQ_BUDDY_MEMO_MODIFY == action) { - qq_create_buddy_memo(gc, (guint32)update_class, QQ_BUDDY_MEMO_MODIFY); + UID mod_uid; + mod_uid = (UID)update_class; + qq_create_buddy_memo(gc, mod_uid, QQ_BUDDY_MEMO_MODIFY); return; } return; @@ -354,9 +358,9 @@ } /* common action, update buddy memo */ - update_buddy_memo(gc, rcv_uid, segments[QQ_MEMO_ALIAS]); + update_buddy_memo(gc, (UID)rcv_uid, segments[QQ_MEMO_ALIAS]); - /* memo is thing that we regard our buddy as, so we need one more buddy_uid */ + /* memo is a thing that we regard our buddy as, so we need one more buddy_uid */ memo_modify_dialogue(gc, rcv_uid, segments, action); break; default: @@ -365,8 +369,12 @@ } } -/* request buddy memo */ -void qq_request_buddy_memo(PurpleConnection *gc, guint32 bd_uid, guint32 update_class, guint32 action) +/* request buddy memo + * + * param: gc, uid, update_class, action + * here, update_class will be set to buddy's uid. because some memo + * packages returned without uid, which will make us confused */ +void qq_request_buddy_memo(PurpleConnection *gc, UID bd_uid, UPDCLS update_class, guint32 action) { guint8 raw_data[16] = {0}; gint bytes; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_memo.h --- a/libpurple/protocols/qq/buddy_memo.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_memo.h Mon Apr 25 20:13:05 2011 +0000 @@ -28,6 +28,7 @@ #include #include "connection.h" #include "blist.h" +#include "qq.h" #define QQ_BUDDY_MEMO_REQUEST_SUCCESS 0x00 @@ -40,9 +41,9 @@ }; -void qq_process_get_buddy_memo(PurpleConnection *gc, guint8* data, gint data_len, guint32 update_class, guint32 action); +void qq_process_get_buddy_memo(PurpleConnection *gc, guint8* data, gint data_len, UPDCLS update_class, guint32 action); -void qq_request_buddy_memo(PurpleConnection *gc, guint32 bd_uid, guint32 update_class, guint32 action); +void qq_request_buddy_memo(PurpleConnection *gc, UID bd_uid, UPDCLS update_class, guint32 action); #endif diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_opt.c --- a/libpurple/protocols/qq/buddy_opt.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Mon Apr 25 20:13:05 2011 +0000 @@ -51,12 +51,12 @@ typedef struct _qq_buddy_req { PurpleConnection *gc; - guint32 uid; + UID uid; guint8 *auth; guint8 auth_len; } qq_buddy_req; -void add_buddy_authorize_input(PurpleConnection *gc, guint32 uid, +void add_buddy_authorize_input(PurpleConnection *gc, UID uid, guint8 *auth, guint8 auth_len); static void buddy_req_free(qq_buddy_req *add_req) @@ -88,7 +88,7 @@ return g; } -static qq_buddy_data *qq_buddy_data_new(guint32 uid) +static qq_buddy_data *qq_buddy_data_new(UID uid) { qq_buddy_data *bd = g_new0(qq_buddy_data, 1); memset(bd, 0, sizeof(qq_buddy_data)); @@ -97,7 +97,7 @@ return bd; } -qq_buddy_data *qq_buddy_data_find(PurpleConnection *gc, guint32 uid) +qq_buddy_data *qq_buddy_data_find(PurpleConnection *gc, UID uid) { gchar *who; PurpleBuddy *buddy; @@ -131,7 +131,7 @@ } /* create purple buddy without data and display with no-auth icon */ -PurpleBuddy *qq_buddy_new(PurpleConnection *gc, guint32 uid) +PurpleBuddy *qq_buddy_new(PurpleConnection *gc, UID uid) { PurpleBuddy *buddy; PurpleGroup *group; @@ -175,7 +175,7 @@ purple_blist_remove_buddy(buddy); } -PurpleBuddy *qq_buddy_find(PurpleConnection *gc, guint32 uid) +PurpleBuddy *qq_buddy_find(PurpleConnection *gc, UID uid) { PurpleBuddy *buddy; gchar *who; @@ -188,7 +188,7 @@ return buddy; } -PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, guint32 uid) +PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, UID uid) { PurpleBuddy *buddy; qq_buddy_data *bd; @@ -213,7 +213,7 @@ } /* send packet to remove a buddy from my buddy list */ -static void request_remove_buddy(PurpleConnection *gc, guint32 uid) +static void request_remove_buddy(PurpleConnection *gc, UID uid) { gchar uid_str[11]; gint bytes; @@ -226,7 +226,7 @@ } static void request_remove_buddy_ex(PurpleConnection *gc, - guint32 uid, guint8 *auth, guint8 auth_len) + UID uid, guint8 *auth, guint8 auth_len) { gint bytes; guint8 *raw_data; @@ -246,7 +246,7 @@ qq_send_cmd_mess(gc, QQ_CMD_REMOVE_BUDDY, raw_data, bytes, 0, uid); } -void qq_request_auth_code(PurpleConnection *gc, guint8 cmd, guint16 sub_cmd, guint32 uid) +void qq_request_auth_code(PurpleConnection *gc, guint8 cmd, guint16 sub_cmd, UID uid) { guint8 raw_data[16]; gint bytes; @@ -260,7 +260,7 @@ qq_send_cmd_mess(gc, QQ_CMD_AUTH_CODE, raw_data, bytes, 0, uid); } -void qq_process_auth_code(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid) +void qq_process_auth_code(PurpleConnection *gc, guint8 *data, gint data_len, UID uid) { gint bytes; guint8 cmd, reply; @@ -308,7 +308,7 @@ buddy_req_free(add_req); } -static void add_buddy_question_input(PurpleConnection *gc, guint32 uid, gchar *question) +static void add_buddy_question_input(PurpleConnection *gc, UID uid, gchar *question) { gchar *who, *msg; qq_buddy_req *add_req; @@ -336,7 +336,7 @@ } void qq_request_question(PurpleConnection *gc, - guint8 cmd, guint32 uid, const gchar *question_utf8, const gchar *answer_utf8) + guint8 cmd, UID uid, const gchar *question_utf8, const gchar *answer_utf8) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes; @@ -371,7 +371,7 @@ return; } -static void request_add_buddy_by_question(PurpleConnection *gc, guint32 uid, +static void request_add_buddy_by_question(PurpleConnection *gc, UID uid, guint8 *code, guint16 code_len) { guint8 raw_data[MAX_PACKET_SIZE - 16]; @@ -395,7 +395,7 @@ qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_AUTH_EX, raw_data, bytes); } -void qq_process_question(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid) +void qq_process_question(PurpleConnection *gc, guint8 *data, gint data_len, UID uid) { gint bytes; guint8 cmd, reply; @@ -461,7 +461,7 @@ } /* try to remove myself from someone's buddy list */ -static void request_buddy_remove_me(PurpleConnection *gc, guint32 uid) +static void request_buddy_remove_me(PurpleConnection *gc, UID uid) { guint8 raw_data[16] = {0}; gint bytes = 0; @@ -474,7 +474,7 @@ } /* try to add a buddy without authentication */ -static void request_add_buddy_no_auth(PurpleConnection *gc, guint32 uid) +static void request_add_buddy_no_auth(PurpleConnection *gc, UID uid) { gchar uid_str[11]; @@ -486,7 +486,7 @@ (guint8 *) uid_str, strlen(uid_str), 0, uid); } -static void request_add_buddy_no_auth_ex(PurpleConnection *gc, guint32 uid) +static void request_add_buddy_no_auth_ex(PurpleConnection *gc, UID uid) { guint bytes; guint8 raw_data[16]; @@ -499,7 +499,7 @@ } /* this buddy needs authentication, text conversion is done at lowest level */ -static void request_add_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text) +static void request_add_buddy_auth(PurpleConnection *gc, UID uid, const gchar response, const gchar *text) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes; @@ -526,7 +526,7 @@ qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_AUTH, raw_data, bytes); } -static void request_add_buddy_auth_ex(PurpleConnection *gc, guint32 uid, +static void request_add_buddy_auth_ex(PurpleConnection *gc, UID uid, const gchar *text, guint8 *auth, guint8 auth_len) { guint8 raw_data[MAX_PACKET_SIZE - 16]; @@ -643,7 +643,7 @@ buddy_req_free(add_req); } -void add_buddy_authorize_input(PurpleConnection *gc, guint32 uid, +void add_buddy_authorize_input(PurpleConnection *gc, UID uid, guint8 *auth, guint8 auth_len) { gchar *who, *msg; @@ -683,7 +683,7 @@ void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { qq_data *qd; - guint32 uid; + UID uid; g_return_if_fail(NULL != gc && NULL != gc->proto_data); g_return_if_fail(buddy != NULL); @@ -733,7 +733,7 @@ } /* process the server reply for my request to remove a buddy */ -void qq_process_remove_buddy(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid) +void qq_process_remove_buddy(PurpleConnection *gc, guint8 *data, gint data_len, UID uid) { PurpleBuddy *buddy = NULL; gchar *msg; @@ -756,7 +756,7 @@ } /* process the server reply for my request to remove myself from a buddy */ -void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid) +void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, UID uid) { gchar *msg; @@ -772,7 +772,7 @@ } void qq_process_add_buddy_no_auth(PurpleConnection *gc, - guint8 *data, gint data_len, guint32 uid) + guint8 *data, gint data_len, UID uid) { qq_data *qd; gchar **segments; @@ -834,11 +834,11 @@ } void qq_process_add_buddy_no_auth_ex(PurpleConnection *gc, - guint8 *data, gint data_len, guint32 uid) + guint8 *data, gint data_len, UID uid) { qq_data *qd; gint bytes; - guint32 dest_uid; + UID dest_uid; guint8 reply; guint8 auth_type; @@ -903,7 +903,7 @@ { qq_data *qd; qq_buddy_data *bd; - guint32 uid; + UID uid; g_return_if_fail(gc != NULL && gc->proto_data != NULL); g_return_if_fail(buddy != NULL); @@ -933,7 +933,7 @@ * otherwise purple segmentation fault */ } -static void buddy_add_input(PurpleConnection *gc, guint32 uid, gchar *reason) +static void buddy_add_input(PurpleConnection *gc, UID uid, gchar *reason) { PurpleAccount *account = purple_connection_get_account(gc); qq_buddy_req *add_req; @@ -967,7 +967,7 @@ static void server_buddy_add_request(PurpleConnection *gc, gchar *from, gchar *to, guint8 *data, gint data_len) { - guint32 uid; + UID uid; gchar *msg, *reason; g_return_if_fail(from != NULL && to != NULL); @@ -996,7 +996,7 @@ gint bytes; guint8 cmd; guint8 reply; - guint32 uid; + UID uid; guint16 flag1, flag2; g_return_if_fail(data != NULL && data_len >= 5); @@ -1026,7 +1026,7 @@ { guint8 *raw_data; gint bytes; - guint32 uid; + UID uid; g_return_if_fail(code != NULL && code_len > 0 && from != NULL); @@ -1073,7 +1073,7 @@ guint8 *data, gint data_len) { gint bytes; - guint32 uid; + UID uid; gchar *msg; guint8 allow_reverse; @@ -1103,7 +1103,7 @@ { PurpleAccount *account = purple_connection_get_account(gc); PurpleBuddy *buddy; - guint32 uid; + UID uid; qq_buddy_req *add_req; gchar *who; gchar *primary; @@ -1177,7 +1177,7 @@ { PurpleAccount *account = purple_connection_get_account(gc); qq_data *qd; - guint32 uid; + UID uid; g_return_if_fail(from != NULL && to != NULL); @@ -1204,7 +1204,7 @@ static void server_buddy_rejected_me(PurpleConnection *gc, gchar *from, gchar *to, guint8 *data, gint data_len) { - guint32 uid; + UID uid; PurpleBuddy *buddy; gchar *msg, *msg_utf8; gint bytes; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/buddy_opt.h --- a/libpurple/protocols/qq/buddy_opt.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/buddy_opt.h Mon Apr 25 20:13:05 2011 +0000 @@ -54,31 +54,31 @@ void qq_remove_buddy_and_me(PurpleBlistNode * node); void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); -void qq_process_remove_buddy(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid); -void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid); +void qq_process_remove_buddy(PurpleConnection *gc, guint8 *data, gint data_len, UID uid); +void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, UID uid); void qq_process_add_buddy_no_auth(PurpleConnection *gc, - guint8 *data, gint data_len, guint32 uid); + guint8 *data, gint data_len, UID uid); void qq_process_add_buddy_no_auth_ex(PurpleConnection *gc, - guint8 *data, gint data_len, guint32 uid); + guint8 *data, gint data_len, UID uid); void qq_process_add_buddy_auth(guint8 *data, gint data_len, PurpleConnection *gc); void qq_process_buddy_from_server(PurpleConnection *gc, int funct, gchar *from, gchar *to, guint8 *data, gint data_len); void qq_process_buddy_check_code(PurpleConnection *gc, guint8 *data, gint data_len); -void qq_request_auth_code(PurpleConnection *gc, guint8 cmd, guint16 sub_cmd, guint32 uid); -void qq_process_auth_code(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid); +void qq_request_auth_code(PurpleConnection *gc, guint8 cmd, guint16 sub_cmd, UID uid); +void qq_process_auth_code(PurpleConnection *gc, guint8 *data, gint data_len, UID uid); void qq_request_question(PurpleConnection *gc, - guint8 cmd, guint32 uid, const gchar *question_utf8, const gchar *answer_utf8); -void qq_process_question(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid); + guint8 cmd, UID uid, const gchar *question_utf8, const gchar *answer_utf8); +void qq_process_question(PurpleConnection *gc, guint8 *data, gint data_len, UID uid); void qq_process_add_buddy_auth_ex(PurpleConnection *gc, guint8 *data, gint data_len, guint32 ship32); -qq_buddy_data *qq_buddy_data_find(PurpleConnection *gc, guint32 uid); +qq_buddy_data *qq_buddy_data_find(PurpleConnection *gc, UID uid); void qq_buddy_data_free(qq_buddy_data *bd); -PurpleBuddy *qq_buddy_new(PurpleConnection *gc, guint32 uid); -PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, guint32 uid); -PurpleBuddy *qq_buddy_find(PurpleConnection *gc, guint32 uid); +PurpleBuddy *qq_buddy_new(PurpleConnection *gc, UID uid); +PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, UID uid); +PurpleBuddy *qq_buddy_find(PurpleConnection *gc, UID uid); PurpleGroup *qq_group_find_or_new(const gchar *group_name); #endif diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/file_trans.c --- a/libpurple/protocols/qq/file_trans.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/file_trans.c Mon Apr 25 20:13:05 2011 +0000 @@ -38,14 +38,12 @@ #include "send_file.h" #include "utils.h" -struct _qq_file_header { +typedef struct _qq_file_header { guint16 client_ver; guint8 file_key; - guint32 sender_uid; - guint32 receiver_uid; -}; - -typedef struct _qq_file_header qq_file_header; + UID sender_uid; + UID receiver_uid; +} qq_file_header; static guint32 _get_file_key(guint8 seed) { @@ -62,12 +60,12 @@ return _get_file_key(seed); } -static guint32 _decrypt_qq_uid(guint32 uid, guint32 key) +static guint32 _decrypt_qq_uid(UID uid, guint32 key) { return ~(uid ^ key); } -static guint32 _encrypt_qq_uid(guint32 uid, guint32 key) +static guint32 _encrypt_qq_uid(UID uid, guint32 key) { return (~uid) ^ key; } @@ -232,7 +230,7 @@ } #endif -static gint _qq_send_file(PurpleConnection *gc, guint8 *data, gint len, guint16 packet_type, guint32 to_uid) +static gint _qq_send_file(PurpleConnection *gc, guint8 *data, gint len, guint16 packet_type, UID to_uid) { guint8 *raw_data; gint bytes = 0; @@ -259,7 +257,7 @@ } /* send a file to udp channel with QQ_FILE_CONTROL_PACKET_TAG */ -void qq_send_file_ctl_packet(PurpleConnection *gc, guint16 packet_type, guint32 to_uid, guint8 hellobyte) +void qq_send_file_ctl_packet(PurpleConnection *gc, guint16 packet_type, UID to_uid, guint8 hellobyte) { qq_data *qd; gint bytes, bytes_expected, encrypted_len; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/file_trans.h --- a/libpurple/protocols/qq/file_trans.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/file_trans.h Mon Apr 25 20:13:05 2011 +0000 @@ -26,6 +26,7 @@ #define _QQ_QQ_FILE_TRANS_H_ #include "server.h" +#include "qq.h" enum { QQ_FILE_CMD_SENDER_SAY_HELLO = 0x31, @@ -59,7 +60,7 @@ #define QQ_FILE_AGENT_PACKET_TAG 0x04 /* #define QQ_PACKET_TAIL 0x03 */ /* all QQ text packets end with it */ -void qq_send_file_ctl_packet(PurpleConnection *gc, guint16 packet_type, guint32 to_uid, guint8 hellobyte); +void qq_send_file_ctl_packet(PurpleConnection *gc, guint16 packet_type, UID to_uid, guint8 hellobyte); void qq_process_recv_file(PurpleConnection *gc, guint8 *data, gint len); /* void qq_send_file_data_packet(PurpleConnection *gc, guint16 packet_type, guint8 sub_type, guint32 fragment_index, guint16 seq, guint8 *data, gint len); */ void qq_xfer_close_file(PurpleXfer *xfer); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group.h --- a/libpurple/protocols/qq/group.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group.h Mon Apr 25 20:13:05 2011 +0000 @@ -40,14 +40,13 @@ QQ_ROOM_ROLE_ADMIN } qq_room_role; -typedef struct _qq_room_data qq_room_data; -struct _qq_room_data { +typedef struct _qq_room_data { /* all these will be saved when we exit Purple */ qq_room_role my_role; /* my role for this room */ guint32 id; guint32 ext_id; guint8 type8; /* permanent or temporory */ - guint32 creator_uid; + UID creator_uid; guint32 category; guint8 auth_type; gchar *title_utf8; @@ -57,7 +56,7 @@ gboolean is_got_buddies; GList *members; -}; +} qq_room_data; GList *qq_chat_info(PurpleConnection *gc); GHashTable *qq_chat_info_defaults(PurpleConnection *gc, const gchar *chat_name); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_im.c --- a/libpurple/protocols/qq/group_im.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_im.c Mon Apr 25 20:13:05 2011 +0000 @@ -161,7 +161,7 @@ } void qq_room_got_chat_in(PurpleConnection *gc, - guint32 room_id, guint32 uid_from, const gchar *msg, time_t in_time) + guint32 room_id, UID uid_from, const gchar *msg, time_t in_time) { PurpleConversation *conv; qq_data *qd; @@ -207,10 +207,11 @@ { gchar *msg_smiley, *msg_fmt, *msg_utf8; gint bytes, tail_len; + qq_data *qd; struct { guint32 ext_id; guint8 type8; - guint32 member_uid; + UID member_uid; guint16 unknown; guint16 msg_seq; time_t send_time; @@ -222,11 +223,15 @@ guint16 content_type; guint8 frag_count, frag_index; guint16 msg_id; + guint32 use_default_font; qq_im_format *fmt = NULL; + qd = (qq_data *) gc->proto_data; /* at least include im_text.msg_len */ g_return_if_fail(data != NULL && data_len > 23); + use_default_font = (qd->custom) & QQ_CUSTOM_USE_DEFAULT_FONT; + /* qq_show_packet("ROOM_IM", data, data_len); */ memset(&im_text, 0, sizeof(im_text)); bytes = 0; @@ -279,8 +284,14 @@ /* group im_group has no flag to indicate whether it has font_attr or not */ msg_smiley = qq_emoticon_to_purple(im_text.msg); if (fmt != NULL) { + purple_debug_info("QQ", "going to use_default_font\n"); + if (QQ_CUSTOM_USE_DEFAULT_FONT == use_default_font) { + qq_im_fmt_reset_font(fmt); + purple_debug_info("QQ", "use_default_font set\n"); + } msg_fmt = qq_im_fmt_to_purple(fmt, msg_smiley); msg_utf8 = qq_to_utf8(msg_fmt, QQ_CHARSET_DEFAULT); + purple_debug_info("QQ", "passed!\n"); g_free(msg_fmt); qq_im_fmt_free(fmt); } else { diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_im.h --- a/libpurple/protocols/qq/group_im.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_im.h Mon Apr 25 20:13:05 2011 +0000 @@ -30,11 +30,16 @@ #include "conversation.h" #include "group.h" +enum { + QQ_CUSTOM_USE_DEFAULT_FONT = 0x00000001, + QQ_CUSTOM_NONE = 0x00000000 +}; + PurpleConversation *qq_room_conv_open(PurpleConnection *gc, qq_room_data *rmd); void qq_room_conv_set_onlines(PurpleConnection *gc, qq_room_data *rmd); void qq_room_got_chat_in(PurpleConnection *gc, - guint32 room_id, guint32 uid_from, const gchar *msg, time_t in_time); + guint32 room_id, UID uid_from, const gchar *msg, time_t in_time); int qq_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags); void qq_process_room_send_im(PurpleConnection *gc, guint8 *data, gint len); @@ -43,3 +48,4 @@ void qq_process_room_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type); #endif + diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_info.c --- a/libpurple/protocols/qq/group_info.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_info.c Mon Apr 25 20:13:05 2011 +0000 @@ -65,7 +65,7 @@ } /* send packet to get info for each group member */ -gint qq_request_room_get_buddies(PurpleConnection *gc, guint32 room_id, guint32 update_class) +gint qq_request_room_get_buddies(PurpleConnection *gc, guint32 room_id, UPDCLS update_class) { guint8 *raw_data; gint bytes, num; @@ -177,7 +177,8 @@ PurpleConversation *conv; guint8 organization, role; guint16 unknown, max_members; - guint32 member_uid, id, ext_id; + UID member_uid; + guint32 id, ext_id; guint32 unknown4; guint8 unknown1; gint bytes, num; @@ -286,7 +287,8 @@ void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc) { - guint32 room_id, member_uid; + guint32 room_id; + UID member_uid; guint8 unknown; gint bytes, num; qq_room_data *rmd; @@ -334,7 +336,8 @@ { gint bytes; gint num; - guint32 id, member_uid; + guint32 id; + UID member_uid; guint16 unknown; qq_room_data *rmd; qq_buddy_data *bd; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_info.h --- a/libpurple/protocols/qq/group_info.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_info.h Mon Apr 25 20:13:05 2011 +0000 @@ -34,7 +34,7 @@ QQ_ROOM_INFO_DISPLAY }; -gint qq_request_room_get_buddies(PurpleConnection *gc, guint32 room_id, guint32 update_class); +gint qq_request_room_get_buddies(PurpleConnection *gc, guint32 room_id, UPDCLS update_class); void qq_process_room_cmd_get_info(guint8 *data, gint len, guint32 action, PurpleConnection *gc); void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_internal.c --- a/libpurple/protocols/qq/group_internal.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_internal.c Mon Apr 25 20:13:05 2011 +0000 @@ -207,7 +207,7 @@ } /* find a qq_buddy_data by uid, called by im.c */ -qq_buddy_data *qq_room_buddy_find(qq_room_data *rmd, guint32 uid) +qq_buddy_data *qq_room_buddy_find(qq_room_data *rmd, UID uid) { GList *list; qq_buddy_data *bd; @@ -226,7 +226,7 @@ } /* remove a qq_buddy_data by uid, called by qq_group_opt.c */ -void qq_room_buddy_remove(qq_room_data *rmd, guint32 uid) +void qq_room_buddy_remove(qq_room_data *rmd, UID uid) { GList *list; qq_buddy_data *bd; @@ -244,7 +244,7 @@ } } -qq_buddy_data *qq_room_buddy_find_or_new(PurpleConnection *gc, qq_room_data *rmd, guint32 member_uid) +qq_buddy_data *qq_room_buddy_find_or_new(PurpleConnection *gc, qq_room_data *rmd, UID member_uid) { qq_buddy_data *member, *bd; PurpleBuddy *buddy; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_internal.h --- a/libpurple/protocols/qq/group_internal.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_internal.h Mon Apr 25 20:13:05 2011 +0000 @@ -36,9 +36,9 @@ void qq_room_remove(PurpleConnection *gc, guint32 id); void qq_room_update_chat_info(PurpleChat *chat, qq_room_data *rmd); -qq_buddy_data *qq_room_buddy_find(qq_room_data *rmd, guint32 uid); -void qq_room_buddy_remove(qq_room_data *rmd, guint32 uid); -qq_buddy_data *qq_room_buddy_find_or_new(PurpleConnection *gc, qq_room_data *rmd, guint32 member_uid); +qq_buddy_data *qq_room_buddy_find(qq_room_data *rmd, UID uid); +void qq_room_buddy_remove(qq_room_data *rmd, UID uid); +qq_buddy_data *qq_room_buddy_find_or_new(PurpleConnection *gc, qq_room_data *rmd, UID member_uid); void qq_room_data_initial(PurpleConnection *gc); void qq_room_data_free_all(PurpleConnection *gc); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_join.c --- a/libpurple/protocols/qq/group_join.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_join.c Mon Apr 25 20:13:05 2011 +0000 @@ -155,7 +155,7 @@ } void qq_send_cmd_group_auth(PurpleConnection *gc, qq_room_data *rmd, - guint8 opt, guint32 uid, const gchar *reason_utf8) + guint8 opt, UID uid, const gchar *reason_utf8) { guint8 raw_data[MAX_PACKET_SIZE - 16]; gint bytes; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/group_join.h --- a/libpurple/protocols/qq/group_join.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/group_join.h Mon Apr 25 20:13:05 2011 +0000 @@ -49,7 +49,7 @@ void qq_request_room_search(PurpleConnection *gc, guint32 ext_id, int action); void qq_process_room_search(PurpleConnection *gc, guint8 *data, gint len, guint32 ship32); -void qq_send_cmd_group_auth(PurpleConnection *gc, qq_room_data *rmd, guint8 opt, guint32 uid, const gchar *reason_utf8); +void qq_send_cmd_group_auth(PurpleConnection *gc, qq_room_data *rmd, guint8 opt, UID uid, const gchar *reason_utf8); void qq_group_join(PurpleConnection *gc, GHashTable *data); void qq_request_room_join(PurpleConnection *gc, qq_room_data *rmd); void qq_room_quit(PurpleConnection *gc, guint32 room_id); @@ -57,3 +57,4 @@ void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc); void qq_process_group_cmd_join_group(guint8 *data, gint len, PurpleConnection *gc); #endif + diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/im.c --- a/libpurple/protocols/qq/im.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/im.c Mon Apr 25 20:13:05 2011 +0000 @@ -67,15 +67,14 @@ QQ_NORMAL_IM_FILE_EX_NOTIFY_IP = 0x87 }; -typedef struct _qq_im_header qq_im_header; -struct _qq_im_header { +typedef struct _qq_im_header { /* this is the common part of normal_text */ guint16 version_from; - guint32 uid_from; - guint32 uid_to; + UID uid_from; + UID uid_to; guint8 session_md5[QQ_KEY_LENGTH]; guint16 im_type; -}; +} qq_im_header; /* read the common parts of the normal_im, * returns the bytes read if succeed, or -1 if there is any error */ @@ -93,11 +92,10 @@ return bytes; } -typedef struct _qq_emoticon qq_emoticon; -struct _qq_emoticon { +typedef struct _qq_emoticon { guint8 symbol; gchar *name; -}; +} qq_emoticon; static gboolean emoticons_is_sorted = FALSE; /* Map for purple smiley convert to qq, need qsort */ @@ -528,7 +526,8 @@ qq_im_format *qq_im_fmt_new(void) { qq_im_format *fmt; - const gchar simsun[] = { 0xcb, 0xce, 0xcc, 0xe5, 0}; /* simsun in Chinese */ + /* '0xcb, 0xce, 0xcc, 0xe5' means Chinese '宋体' in utf8 */ + const gchar simsun[] = { 0xcb, 0xce, 0xcc, 0xe5, 0}; fmt = g_new0(qq_im_format, 1); memset(fmt, 0, sizeof(qq_im_format)); @@ -541,6 +540,17 @@ return fmt; } +void qq_im_fmt_reset_font(qq_im_format *fmt) +{ + const gchar simsun[] = {0xcb, 0xce, 0xcc, 0xe5, 0x00}; + g_return_if_fail(NULL != fmt); + + if (NULL != fmt->font) { + g_free(fmt->font); + fmt->font = g_strdup(simsun); + } +} + qq_im_format *qq_im_fmt_new_by_purple(const gchar *msg) { qq_im_format *fmt; @@ -1036,7 +1046,7 @@ } /* send an IM to uid_to */ -static void request_send_im(PurpleConnection *gc, guint32 uid_to, gint type, +static void request_send_im(PurpleConnection *gc, UID uid_to, gint type, qq_im_format *fmt, gchar *msg, guint8 id, guint8 frag_count, guint8 frag_index) { qq_data *qd; @@ -1241,7 +1251,7 @@ gint qq_send_im(PurpleConnection *gc, const gchar *who, const gchar *what, PurpleMessageFlags flags) { qq_data *qd; - guint32 uid_to; + UID uid_to; gint type; qq_im_format *fmt; gchar *msg_stripped, *tmp; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/im.h --- a/libpurple/protocols/qq/im.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/im.h Mon Apr 25 20:13:05 2011 +0000 @@ -49,6 +49,10 @@ }; typedef struct { + /* attr: + bit0-4 for font size, bit5 for bold, + bit6 for italic, bit7 for underline + */ guint8 attr; guint8 rgb[3]; guint16 charset; @@ -61,6 +65,7 @@ qq_im_format *qq_im_fmt_new(void); void qq_im_fmt_free(qq_im_format *fmt); +void qq_im_fmt_reset_font(qq_im_format *fmt); qq_im_format *qq_im_fmt_new_by_purple(const gchar *msg); gchar *qq_im_fmt_to_purple(qq_im_format *fmt, gchar *text); gboolean qq_im_smiley_none(const gchar *msg); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq.c Mon Apr 25 20:13:05 2011 +0000 @@ -173,6 +173,13 @@ qd->is_show_news = purple_account_get_bool(account, "show_news", TRUE); qd->is_show_chat = purple_account_get_bool(account, "show_chat", TRUE); + if (purple_account_get_bool(account, "default_font", FALSE)) { + qd->custom = QQ_CUSTOM_USE_DEFAULT_FONT; + } + else { + qd->custom = QQ_CUSTOM_NONE; + } + qd->resend_times = purple_prefs_get_int("/plugins/prpl/qq/resend_times"); if (qd->resend_times <= 1) qd->itv_config.resend = 4; @@ -443,7 +450,7 @@ /* send packet to get who's detailed information */ static void qq_show_buddy_info(PurpleConnection *gc, const gchar *who) { - guint32 uid; + UID uid; qq_data *qd; qd = gc->proto_data; @@ -823,7 +830,7 @@ PurpleBuddy *buddy; qq_buddy_data *bd; PurpleConnection *gc; - guint32 bd_uid; + UID bd_uid; g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); @@ -927,7 +934,7 @@ { qq_data *qd; gchar *uid_str; - guint32 uid; + UID uid; purple_debug_info("QQ", "Get chat buddy info of %s\n", who); g_return_if_fail(who != NULL); @@ -1035,7 +1042,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = { @@ -1142,6 +1151,9 @@ option = purple_account_option_bool_new(_("Show chat room when msg comes"), "show_chat", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_bool_new(_("Use default font"), "default_font", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_int_new(_("Keep alive interval (seconds)"), "keep_alive_interval", 60); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq.h --- a/libpurple/protocols/qq/qq.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq.h Mon Apr 25 20:13:05 2011 +0000 @@ -39,22 +39,19 @@ #define qq_strlen(s) ((s)!=NULL?strlen(s):0) #define qq_strcmp(s1,s2) ((s1)!=NULL && (s2)!=NULL?strcmp(s1,s2):0) -typedef struct _qq_data qq_data; -typedef struct _qq_buddy_data qq_buddy_data; -typedef struct _qq_interval qq_interval; -typedef struct _qq_net_stat qq_net_stat; -typedef struct _qq_login_data qq_login_data; -typedef struct _qq_captcha_data qq_captcha_data; +/* business logic layer */ +typedef guint32 UPDCLS; +typedef guint32 UID; -struct _qq_captcha_data { +typedef struct _qq_captcha_data { guint8 *token; guint16 token_len; guint8 next_index; guint8 *data; guint16 data_len; -}; +} qq_captcha_data; -struct _qq_login_data { +typedef struct _qq_login_data { guint8 random_key[QQ_KEY_LENGTH]; /* first encrypt key generated by client */ guint8 *token; /* get from server */ guint8 token_len; @@ -67,24 +64,24 @@ guint8 *login_token; guint16 login_token_len; guint8 login_key[QQ_KEY_LENGTH]; -}; +} qq_login_data; -struct _qq_interval { +typedef struct _qq_interval { gint resend; gint keep_alive; gint update; -}; +} qq_interval; -struct _qq_net_stat { +typedef struct _qq_net_stat { glong sent; glong resend; glong lost; glong rcved; glong rcved_dup; -}; +} qq_net_stat; -struct _qq_buddy_data { - guint32 uid; +typedef struct _qq_buddy_data { + UID uid; guint16 face; /* index: 0 - 299 */ guint8 age; guint8 gender; @@ -104,7 +101,7 @@ gchar** memo; gint8 role; /* role in group, used only in group->members list */ -}; +} qq_buddy_data; typedef struct _qq_connection qq_connection; struct _qq_connection { @@ -118,7 +115,7 @@ int tcp_rxlen; }; -struct _qq_data { +typedef struct _qq_data { PurpleConnection *gc; GSList *openconns; @@ -153,7 +150,7 @@ GList *transactions; /* check ack packet and resend */ - guint32 uid; /* QQ number */ + UID uid; /* QQ number */ qq_login_data ld; qq_captcha_data captcha; @@ -187,8 +184,9 @@ gboolean is_show_notice; gboolean is_show_news; gboolean is_show_chat; + guint32 custom; guint16 send_im_id; /* send IM sequence number */ -}; +} qq_data; #endif diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_base.c --- a/libpurple/protocols/qq/qq_base.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_base.c Mon Apr 25 20:13:05 2011 +0000 @@ -42,7 +42,7 @@ #include "utils.h" /* generate a md5 key using uid and session_key */ -static void get_session_md5(guint8 *session_md5, guint32 uid, guint8 *session_key) +static void get_session_md5(guint8 *session_md5, UID uid, guint8 *session_key) { guint8 src[QQ_KEY_LENGTH + QQ_KEY_LENGTH]; gint bytes = 0; @@ -60,7 +60,7 @@ gint bytes; guint8 ret; - guint32 uid; + UID uid; struct in_addr ip; guint16 port; struct tm *tm_local; @@ -151,7 +151,7 @@ gint bytes; struct { guint8 result; - guint32 uid; + UID uid; struct in_addr new_server_ip; guint16 new_server_port; } packet; @@ -1236,7 +1236,7 @@ qq_data *qd; gint bytes; guint8 ret; - guint32 uid; + UID uid; gchar *error; gchar *msg; gchar *msg_utf8; @@ -1427,7 +1427,7 @@ qq_data *qd; gint bytes; guint8 ret; - guint32 uid; + UID uid; gchar *error; gchar *msg; gchar *msg_utf8; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_base.h --- a/libpurple/protocols/qq/qq_base.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_base.h Mon Apr 25 20:13:05 2011 +0000 @@ -28,12 +28,12 @@ #include #include "connection.h" -#define QQ_LOGIN_REPLY_OK 0x00 +#define QQ_LOGIN_REPLY_OK 0x00 #define QQ_LOGIN_REPLY_REDIRECT 0x01 /* defined by myself */ #define QQ_LOGIN_REPLY_CAPTCHA_DLG 0xfd -#define QQ_LOGIN_REPLY_NEXT_TOKEN_EX 0xfe -#define QQ_LOGIN_REPLY_ERR 0xff +#define QQ_LOGIN_REPLY_NEXT_TOKEN_EX 0xfe +#define QQ_LOGIN_REPLY_ERR 0xff #define QQ_LOGIN_MODE_NORMAL 0x0a #define QQ_LOGIN_MODE_AWAY 0x1e @@ -76,3 +76,4 @@ void qq_request_login_2008(PurpleConnection *gc); guint8 qq_process_login_2008( PurpleConnection *gc, guint8 *data, gint data_len); #endif + diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_define.c --- a/libpurple/protocols/qq/qq_define.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_define.c Mon Apr 25 20:13:05 2011 +0000 @@ -118,6 +118,8 @@ return "QQMac 1.0 preview1 build 670"; case QQ_CLIENT_1441: return "QQ2009 preview2"; + case QQ_CLIENT_1663: + return "QQ2009"; case QQ_SERVER_0100: return "QQ Server 0100"; default: diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_define.h --- a/libpurple/protocols/qq/qq_define.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_define.h Mon Apr 25 20:13:05 2011 +0000 @@ -35,7 +35,9 @@ #define QQ_CLIENT_0D55 0x0d55 /* QQ2005 used by openq before */ #define QQ_CLIENT_111D 0x111D /* QQ2007 */ -#define QQ_CLIENT_115B 0x115B /* QQ2008 He Sui*/ +#define QQ_CLIENT_115B 0x115B /* QQ2008 He Sui */ +#define QQ_CLIENT_1663 0x1663 /* QQ2009 Release */ +#define QQ_CLIENT_1801 0x1801 /* QQ2009 International Beta1 */ const gchar *qq_get_ver_desc(gint source); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_network.c --- a/libpurple/protocols/qq/qq_network.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_network.c Mon Apr 25 20:13:05 2011 +0000 @@ -42,11 +42,11 @@ #define QQ_DEFAULT_PORT 8000 /* set QQ_CONNECT_MAX to 1, when test reconnecting */ -#define QQ_CONNECT_MAX 3 +#define QQ_CONNECT_MAX 3 #define QQ_CONNECT_INTERVAL 2 -#define QQ_CONNECT_CHECK 5 -#define QQ_KEEP_ALIVE_INTERVAL 60 -#define QQ_TRANS_INTERVAL 10 +#define QQ_CONNECT_CHECK 5 +#define QQ_KEEP_ALIVE_INTERVAL 60 +#define QQ_TRANS_INTERVAL 10 gboolean connect_to_server(PurpleConnection *gc, gchar *server, gint port); @@ -63,6 +63,7 @@ static qq_connection *connection_create(qq_data *qd, int fd) { qq_connection *ret = g_new0(qq_connection, 1); + g_return_val_if_fail(ret != NULL, NULL); ret->fd = fd; qd->openconns = g_slist_append(qd->openconns, ret); return ret; @@ -268,7 +269,7 @@ guint16 seq; /* May be ack_seq or send_seq, depends on cmd */ guint8 room_cmd; guint32 room_id; - guint32 update_class; + UPDCLS update_class; guint32 ship32; int ret; @@ -772,9 +773,14 @@ } /* _qq_show_socket("Got login socket", source); */ + /* ok, already connected to the server */ qd->fd = source; conn = connection_create(qd, source); + g_return_if_fail( conn != NULL ); + if (qd->use_tcp) { + /* events which match "PURPLE_INPUT_READ" of + * "source" would trigger the callback function */ conn->input_handler = purple_input_add(source, PURPLE_INPUT_READ, tcp_pending, gc); } else { conn->input_handler = purple_input_add(source, PURPLE_INPUT_READ, udp_pending, gc); @@ -1131,7 +1137,7 @@ /* Encrypt data with session_key, and send packet out */ static gint send_cmd_detail(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len, gboolean is_save2trans, - guint32 update_class, guint32 ship32) + UPDCLS update_class, guint32 ship32) { qq_data *qd; guint8 *encrypted; @@ -1161,7 +1167,7 @@ } gint qq_send_cmd_mess(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len, - guint32 update_class, guint32 ship32) + UPDCLS update_class, guint32 ship32) { qq_data *qd; guint16 seq; @@ -1235,7 +1241,7 @@ } static gint send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len, guint32 update_class, guint32 ship32) + guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32) { qq_data *qd; guint8 *buf; @@ -1289,7 +1295,7 @@ } gint qq_send_room_cmd_mess(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len, guint32 update_class, guint32 ship32) + guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32) { g_return_val_if_fail(room_cmd > 0, -1); return send_room_cmd(gc, room_cmd, room_id, data, data_len, update_class, ship32); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_network.h --- a/libpurple/protocols/qq/qq_network.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_network.h Mon Apr 25 20:13:05 2011 +0000 @@ -39,7 +39,7 @@ guint8 *encrypted_data, gint encrypted_len, gboolean is_save2trans); gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, guint8 *data, gint datalen); gint qq_send_cmd_mess(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len, - guint32 update_class, guint32 ship32); + UPDCLS update_class, guint32 ship32); gint qq_send_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len); @@ -47,7 +47,7 @@ gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len); gint qq_send_room_cmd_mess(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len, guint32 update_class, guint32 ship32); + guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32); gint qq_send_room_cmd_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, guint8 *data, gint data_len); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_process.c Mon Apr 25 20:13:05 2011 +0000 @@ -254,8 +254,8 @@ gint bytes; struct { - guint32 uid_from; - guint32 uid_to; + UID uid_from; + UID uid_to; guint32 seq; struct in_addr ip_from; guint16 port_from; @@ -725,7 +725,7 @@ void qq_proc_room_cmds(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, - guint32 update_class, guint32 ship32) + UPDCLS update_class, guint32 ship32) { qq_data *qd; guint8 *data; @@ -861,7 +861,7 @@ } guint8 qq_proc_login_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq, - guint8 *rcved, gint rcved_len, guint32 update_class, guint32 ship32) + guint8 *rcved, gint rcved_len, UPDCLS update_class, guint32 ship32) { qq_data *qd; guint8 *data = NULL; @@ -1013,7 +1013,7 @@ } void qq_proc_client_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq, - guint8 *rcved, gint rcved_len, guint32 update_class, guint32 ship32) + guint8 *rcved, gint rcved_len, UPDCLS update_class, guint32 ship32) { qq_data *qd; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_process.h --- a/libpurple/protocols/qq/qq_process.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_process.h Mon Apr 25 20:13:05 2011 +0000 @@ -39,12 +39,12 @@ }; guint8 qq_proc_login_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq, - guint8 *rcved, gint rcved_len, guint32 update_class, guint32 ship32); + guint8 *rcved, gint rcved_len, UPDCLS update_class, guint32 ship32); void qq_proc_client_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq, - guint8 *rcved, gint rcved_len, guint32 update_class, guint32 ship32); + guint8 *rcved, gint rcved_len, UPDCLS update_class, guint32 ship32); void qq_proc_room_cmds(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, - guint32 update_class, guint32 ship32); + UPDCLS update_class, guint32 ship32); void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_trans.c --- a/libpurple/protocols/qq/qq_trans.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Mon Apr 25 20:13:05 2011 +0000 @@ -42,25 +42,6 @@ QQ_TRANS_IS_REPLY = 0x08 /* server command before login*/ }; -struct _qq_transaction { - guint8 flag; - guint16 seq; - guint16 cmd; - - guint8 room_cmd; - guint32 room_id; - - guint8 *data; - gint data_len; - - gint fd; - gint send_retries; - gint rcved_times; - gint scan_times; - - guint32 update_class; - guint32 ship32; -}; gboolean qq_trans_is_server(qq_transaction *trans) { @@ -107,7 +88,7 @@ } static qq_transaction *trans_create(PurpleConnection *gc, gint fd, - guint16 cmd, guint16 seq, guint8 *data, gint data_len, guint32 update_class, guint32 ship32) + guint16 cmd, guint16 seq, guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32) { qq_transaction *trans; @@ -178,7 +159,7 @@ } void qq_trans_add_client_cmd(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *data, gint data_len, guint32 update_class, guint32 ship32) + guint16 cmd, guint16 seq, guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, update_class, ship32); @@ -218,7 +199,7 @@ void qq_trans_add_room_cmd(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len, - guint32 update_class, guint32 ship32) + UPDCLS update_class, guint32 ship32) { qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans = trans_create(gc, qd->fd, QQ_CMD_ROOM, seq, data, data_len, diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/qq_trans.h --- a/libpurple/protocols/qq/qq_trans.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/qq_trans.h Mon Apr 25 20:13:05 2011 +0000 @@ -28,7 +28,25 @@ #include #include "qq.h" -typedef struct _qq_transaction qq_transaction; +typedef struct _qq_transaction { + guint8 flag; + guint16 seq; + guint16 cmd; + + guint8 room_cmd; + guint32 room_id; + + guint8 *data; + gint data_len; + + gint fd; + gint send_retries; + gint rcved_times; + gint scan_times; + + UPDCLS update_class; + guint32 ship32; +} qq_transaction; qq_transaction *qq_trans_find_rcved(PurpleConnection *gc, guint16 cmd, guint16 seq); gboolean qq_trans_is_server(qq_transaction *trans) ; @@ -39,10 +57,10 @@ guint32 qq_trans_get_ship(qq_transaction *trans); void qq_trans_add_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, - guint8 *data, gint data_len, guint32 update_class, guint32 ship32); + guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32); void qq_trans_add_room_cmd(PurpleConnection *gc, guint16 seq, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len, guint32 update_class, guint32 ship32); + guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32); void qq_trans_add_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); void qq_trans_add_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/send_file.c --- a/libpurple/protocols/qq/send_file.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/send_file.c Mon Apr 25 20:13:05 2011 +0000 @@ -278,7 +278,7 @@ /* fill in the common information of file transfer */ static gint _qq_create_packet_file_header -(guint8 *raw_data, guint32 to_uid, guint16 message_type, qq_data *qd, gboolean seq_ack) +(guint8 *raw_data, UID to_uid, guint16 message_type, qq_data *qd, gboolean seq_ack) { gint bytes; time_t now; @@ -430,7 +430,7 @@ } /* create the QQ_FILE_TRANS_REQ packet with file infomations */ -static void _qq_send_packet_file_request (PurpleConnection *gc, guint32 to_uid, gchar *filename, gint filesize) +static void _qq_send_packet_file_request (PurpleConnection *gc, UID to_uid, gchar *filename, gint filesize) { qq_data *qd; guint8 *raw_data; @@ -482,7 +482,7 @@ } /* tell the buddy we want to accept the file */ -static void _qq_send_packet_file_accept(PurpleConnection *gc, guint32 to_uid) +static void _qq_send_packet_file_accept(PurpleConnection *gc, UID to_uid) { qq_data *qd; guint8 *raw_data; @@ -520,7 +520,7 @@ packet_len, bytes); } -static void _qq_send_packet_file_notifyip(PurpleConnection *gc, guint32 to_uid) +static void _qq_send_packet_file_notifyip(PurpleConnection *gc, UID to_uid) { PurpleXfer *xfer; ft_info *info; @@ -552,7 +552,7 @@ } /* tell the buddy we don't want the file */ -static void _qq_send_packet_file_reject (PurpleConnection *gc, guint32 to_uid) +static void _qq_send_packet_file_reject (PurpleConnection *gc, UID to_uid) { qq_data *qd; guint8 *raw_data; @@ -576,7 +576,7 @@ } /* tell the buddy to cancel transfer */ -static void _qq_send_packet_file_cancel (PurpleConnection *gc, guint32 to_uid) +static void _qq_send_packet_file_cancel (PurpleConnection *gc, UID to_uid) { qq_data *qd; guint8 *raw_data; @@ -611,7 +611,7 @@ { PurpleConnection *gc; PurpleAccount *account; - guint32 to_uid; + UID to_uid; const gchar *filename; gchar *base_filename; @@ -678,7 +678,7 @@ /* process reject im for file transfer request */ void qq_process_recv_file_reject (guint8 *data, gint data_len, - guint32 sender_uid, PurpleConnection *gc) + UID sender_uid, PurpleConnection *gc) { gchar *msg, *filename; qq_data *qd; @@ -708,7 +708,7 @@ /* process cancel im for file transfer request */ void qq_process_recv_file_cancel (guint8 *data, gint data_len, - guint32 sender_uid, PurpleConnection *gc) + UID sender_uid, PurpleConnection *gc) { gchar *msg, *filename; qq_data *qd; @@ -738,7 +738,7 @@ } /* process accept im for file transfer request */ -void qq_process_recv_file_accept(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc) +void qq_process_recv_file_accept(guint8 *data, gint data_len, UID sender_uid, PurpleConnection *gc) { qq_data *qd; gint bytes; @@ -764,7 +764,7 @@ } /* process request from buddy's im for file transfer request */ -void qq_process_recv_file_request(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection * gc) +void qq_process_recv_file_request(guint8 *data, gint data_len, UID sender_uid, PurpleConnection * gc) { qq_data *qd; PurpleXfer *xfer; @@ -874,7 +874,7 @@ } void qq_process_recv_file_notify(guint8 *data, gint data_len, - guint32 sender_uid, PurpleConnection *gc) + UID sender_uid, PurpleConnection *gc) { gint bytes; qq_data *qd; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/send_file.h --- a/libpurple/protocols/qq/send_file.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/send_file.h Mon Apr 25 20:13:05 2011 +0000 @@ -29,7 +29,7 @@ #include "qq.h" typedef struct _ft_info { - guint32 to_uid; + UID to_uid; guint16 send_seq; guint8 file_session_key[QQ_KEY_LENGTH]; guint8 conn_method; @@ -67,11 +67,11 @@ gboolean use_major; } ft_info; -void qq_process_recv_file_accept(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_reject(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_cancel(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_request(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); -void qq_process_recv_file_notify(guint8 *data, gint data_len, guint32 sender_uid, PurpleConnection *gc); +void qq_process_recv_file_accept(guint8 *data, gint data_len, UID sender_uid, PurpleConnection *gc); +void qq_process_recv_file_reject(guint8 *data, gint data_len, UID sender_uid, PurpleConnection *gc); +void qq_process_recv_file_cancel(guint8 *data, gint data_len, UID sender_uid, PurpleConnection *gc); +void qq_process_recv_file_request(guint8 *data, gint data_len, UID sender_uid, PurpleConnection *gc); +void qq_process_recv_file_notify(guint8 *data, gint data_len, UID sender_uid, PurpleConnection *gc); gboolean qq_can_receive_file(PurpleConnection *gc, const char *who); void qq_send_file(PurpleConnection *gc, const char *who, const char *file); gint qq_get_conn_info(ft_info *info, guint8 *data); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/utils.c --- a/libpurple/protocols/qq/utils.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/utils.c Mon Apr 25 20:13:05 2011 +0000 @@ -131,9 +131,9 @@ } /* convert Purple name to original QQ UID */ -guint32 purple_name_to_uid(const gchar *const name) +UID purple_name_to_uid(const gchar *const name) { - guint32 ret; + UID ret; g_return_val_if_fail(name != NULL, 0); ret = strtoul(name, NULL, 10); @@ -168,7 +168,7 @@ /* convert a QQ UID to a unique name of Purple * the return needs to be freed */ -gchar *uid_to_purple_name(guint32 uid) +gchar *uid_to_purple_name(UID uid) { return g_strdup_printf("%u", uid); } diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/qq/utils.h --- a/libpurple/protocols/qq/utils.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/qq/utils.h Mon Apr 25 20:13:05 2011 +0000 @@ -27,6 +27,7 @@ #include #include +#include "qq.h" #include "debug.h" @@ -40,8 +41,8 @@ gchar *gen_ip_str(guint8 *ip); guint8 *str_ip_gen(gchar *str); -guint32 purple_name_to_uid(const gchar *name); -gchar *uid_to_purple_name(guint32 uid); +UID purple_name_to_uid(const gchar *name); +gchar *uid_to_purple_name(UID uid); gchar *try_dump_as_gbk(const guint8 *const data, gint len); diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/silc/silc.c --- a/libpurple/protocols/silc/silc.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/silc/silc.c Mon Apr 25 20:13:05 2011 +0000 @@ -654,6 +654,8 @@ { SilcPurple sg = (SilcPurple)context; + purple_debug_info("silc", "Finalizing SilcPurple %p\n", sg); + silc_client_stop(sg->client, NULL, NULL); silc_client_free(sg->client); if (sg->sha1hash) @@ -714,6 +716,8 @@ #endif /* __SILC_TOOLKIT_VERSION */ purple_timeout_remove(sg->scheduler); + + purple_debug_info("silc", "Scheduling destruction of SilcPurple %p\n", sg); purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg); } @@ -2119,7 +2123,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/silc10/silc.c --- a/libpurple/protocols/silc10/silc.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/silc10/silc.c Mon Apr 25 20:13:05 2011 +0000 @@ -1845,7 +1845,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/simple/simple.c --- a/libpurple/protocols/simple/simple.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/simple/simple.c Mon Apr 25 20:13:05 2011 +0000 @@ -2112,7 +2112,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/yahoo/libyahoo.c --- a/libpurple/protocols/yahoo/libyahoo.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/yahoo/libyahoo.c Mon Apr 25 20:13:05 2011 +0000 @@ -267,7 +267,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/yahoo/libyahoojp.c --- a/libpurple/protocols/yahoo/libyahoojp.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/yahoo/libyahoojp.c Mon Apr 25 20:13:05 2011 +0000 @@ -163,7 +163,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/yahoo/libymsg.c --- a/libpurple/protocols/yahoo/libymsg.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/yahoo/libymsg.c Mon Apr 25 20:13:05 2011 +0000 @@ -842,7 +842,7 @@ break; } - if (*stat == '1') + if (stat && *stat == '1') serv_got_typing(gc, fed_from, 0, PURPLE_TYPING); else serv_got_typing_stopped(gc, fed_from); @@ -864,7 +864,7 @@ yahoo_friend_set_game(f, NULL); - if (*stat == '1') { + if (stat && *stat == '1') { yahoo_friend_set_game(f, game); if (bud) yahoo_update_status(gc, from, f); @@ -922,6 +922,11 @@ l = l->next; } + if(!sms) { + purple_debug_info("yahoo", "Received a malformed SMS packet!\n"); + return; + } + if( (pkt->status == -1) || (pkt->status == YAHOO_STATUS_DISCONNECTED) ) { if (server_msg) { PurpleConversation *c; @@ -3985,7 +3990,6 @@ void yahoo_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) { YahooFriend *f; - char *escaped; char *status = NULL; const char *presence = NULL; PurpleAccount *account; @@ -4024,14 +4028,12 @@ } if (status != NULL) { - escaped = g_markup_escape_text(status, strlen(status)); - purple_notify_user_info_add_pair(user_info, _("Status"), escaped); + purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), status); g_free(status); - g_free(escaped); } if (presence != NULL) - purple_notify_user_info_add_pair(user_info, _("Presence"), presence); + purple_notify_user_info_add_pair_plaintext(user_info, _("Presence"), presence); if (f && full) { YahooPersonalDetails *ypd = &f->ypd; diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/yahoo/yahoo_profile.c --- a/libpurple/protocols/yahoo/yahoo_profile.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/yahoo/yahoo_profile.c Mon Apr 25 20:13:05 2011 +0000 @@ -701,14 +701,12 @@ if (b) { const char *balias = purple_buddy_get_local_buddy_alias(b); if(balias && balias[0]) { - char *aliastext = g_markup_escape_text(balias, -1); - purple_notify_user_info_add_pair(user_info, _("Alias"), aliastext); - g_free(aliastext); + purple_notify_user_info_add_pair_plaintext(user_info, _("Alias"), balias); } #if 0 if (b->idle > 0) { char *idletime = purple_str_seconds_to_string(time(NULL) - b->idle); - purple_notify_user_info_add_pair(user_info, _("Idle"), idletime); + purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), idletime); g_free(idletime); } #endif @@ -719,7 +717,7 @@ if ((f = yahoo_friend_find(info_data->gc, purple_buddy_get_name(b)))) { const char *ip; if ((ip = yahoo_friend_get_ip(f))) - purple_notify_user_info_add_pair(user_info, _("IP Address"), ip); + purple_notify_user_info_add_pair_plaintext(user_info, _("IP Address"), ip); } } } diff -r a92f4cb593a4 -r 974722699032 libpurple/protocols/zephyr/zephyr.c --- a/libpurple/protocols/zephyr/zephyr.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/protocols/zephyr/zephyr.c Mon Apr 25 20:13:05 2011 +0000 @@ -2911,7 +2911,9 @@ NULL, /* get_media_caps */ NULL, /* get_moods */ NULL, /* set_public_alias */ - NULL /* get_public_alias */ + NULL, /* get_public_alias */ + NULL, /* add_buddy_with_invite */ + NULL /* add_buddies_with_invite */ }; static PurplePluginInfo info = { diff -r a92f4cb593a4 -r 974722699032 libpurple/prpl.h --- a/libpurple/prpl.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/prpl.h Mon Apr 25 20:13:05 2011 +0000 @@ -202,7 +202,14 @@ * Used as a hint that unknown commands should not be sent as messages. * @since 2.1.0 */ - OPT_PROTO_SLASH_COMMANDS_NATIVE = 0x00000400 + OPT_PROTO_SLASH_COMMANDS_NATIVE = 0x00000400, + + /** + * Indicates that this protocol supports sending a user-supplied message + * along with an invitation. + * @since 2.8.0 + */ + OPT_PROTO_INVITE_MESSAGE = 0x00000800 } PurpleProtocolOptions; @@ -333,6 +340,9 @@ * already in the specified group. If the protocol supports * authorization and the user is not already authorized to see the * status of \a buddy, \a add_buddy should request authorization. + * + * @deprecated Since 2.8.0, add_buddy_with_invite is preferred. + * @see add_buddy_with_invite */ void (*add_buddy)(PurpleConnection *, PurpleBuddy *buddy, PurpleGroup *group); void (*add_buddies)(PurpleConnection *, GList *buddies, GList *groups); @@ -622,6 +632,21 @@ void (*get_public_alias)(PurpleConnection *gc, PurpleGetPublicAliasSuccessCallback success_cb, PurpleGetPublicAliasFailureCallback failure_cb); + + /** + * Add a buddy to a group on the server. + * + * This PRPL function may be called in situations in which the buddy is + * already in the specified group. If the protocol supports + * authorization and the user is not already authorized to see the + * status of \a buddy, \a add_buddy should request authorization. + * + * If authorization is required, then use the supplied invite message. + * + * @since 2.8.0 + */ + void (*add_buddy_with_invite)(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group, const char *message); + void (*add_buddies_with_invite)(PurpleConnection *pc, GList *buddies, GList *groups, const char *message); }; #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \ diff -r a92f4cb593a4 -r 974722699032 libpurple/purple-url-handler --- a/libpurple/purple-url-handler Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/purple-url-handler Mon Apr 25 20:13:05 2011 +0000 @@ -73,7 +73,7 @@ def findaccount(protocolname, accountname="", matcher=None): if matcher: for account in cpurple.PurpleAccountsGetAll(): - if (protocolname != cpurple.PurpleAccountGetProtocolID(account)) or \ + if (protocolname != cpurple.PurpleAccountGetProtocolId(account)) or \ (accountname != "" and accountname != cpurple.PurpleAccountGetUsername(account)): continue if matcher(account): @@ -188,7 +188,7 @@ print "Invalid irc URI: %s" % uri return - server = urllib.unquote_plus(match.group(2)) or "" + server = urllib.unquote_plus(match.group(2) or "") target = match.group(3) or "" query = match.group(5) or "" diff -r a92f4cb593a4 -r 974722699032 libpurple/signals.c --- a/libpurple/signals.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/signals.c Mon Apr 25 20:13:05 2011 +0000 @@ -818,6 +818,21 @@ *return_val = GINT_TO_POINTER(ret_val); } + void +purple_marshal_INT__POINTER_POINTER_POINTER( + PurpleCallback cb, va_list args, void *data, void **return_val) +{ + gint ret_val; + void *arg1 = va_arg(args, void *); + void *arg2 = va_arg(args, void *); + void *arg3 = va_arg(args, void *); + + ret_val = ((gint (*)(void *, void *, void *, void *))cb)(arg1, arg2, arg3, data); + + if (return_val != NULL) + *return_val = GINT_TO_POINTER(ret_val); +} + void purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER( PurpleCallback cb, va_list args, void *data, void **return_val) diff -r a92f4cb593a4 -r 974722699032 libpurple/signals.h --- a/libpurple/signals.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/signals.h Mon Apr 25 20:13:05 2011 +0000 @@ -330,6 +330,8 @@ PurpleCallback cb, va_list args, void *data, void **return_val); void purple_marshal_INT__POINTER_POINTER( PurpleCallback cb, va_list args, void *data, void **return_val); +void purple_marshal_INT__POINTER_POINTER_POINTER( + PurpleCallback cb, va_list args, void *data, void **return_val); void purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER( PurpleCallback cb, va_list args, void *data, void **return_val); diff -r a92f4cb593a4 -r 974722699032 libpurple/tests/Makefile.am --- a/libpurple/tests/Makefile.am Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/tests/Makefile.am Mon Apr 25 20:13:05 2011 +0000 @@ -14,6 +14,7 @@ test_jabber_digest_md5.c \ test_jabber_jutil.c \ test_jabber_scram.c \ + test_oscar_util.c \ test_qq.c \ test_yahoo_util.c \ test_util.c \ @@ -30,6 +31,7 @@ check_libpurple_LDADD=\ $(top_builddir)/libpurple/protocols/jabber/libjabber.la \ + $(top_builddir)/libpurple/protocols/oscar/liboscar.la \ $(top_builddir)/libpurple/protocols/qq/libqq_tmp.la \ $(top_builddir)/libpurple/protocols/yahoo/libymsg.la \ $(top_builddir)/libpurple/libpurple.la \ diff -r a92f4cb593a4 -r 974722699032 libpurple/tests/check_libpurple.c --- a/libpurple/tests/check_libpurple.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/tests/check_libpurple.c Mon Apr 25 20:13:05 2011 +0000 @@ -88,6 +88,7 @@ srunner_add_suite(sr, jabber_digest_md5_suite()); srunner_add_suite(sr, jabber_jutil_suite()); srunner_add_suite(sr, jabber_scram_suite()); + srunner_add_suite(sr, oscar_util_suite()); srunner_add_suite(sr, qq_suite()); srunner_add_suite(sr, yahoo_util_suite()); srunner_add_suite(sr, util_suite()); diff -r a92f4cb593a4 -r 974722699032 libpurple/tests/test_oscar_util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/tests/test_oscar_util.c Mon Apr 25 20:13:05 2011 +0000 @@ -0,0 +1,47 @@ +#include + +#include "tests.h" +#include "../protocols/oscar/oscar.h" + +START_TEST(test_oscar_util_name_compare) +{ + int i; + const char *good[] = { + "test", + "TEST", + "Test", + "teSt", + " TesT", + "test ", + " T E s T " + }; + const char *bad[] = { + "toast", + "test@example.com", + "test@aim.com" + }; + + for (i = 0; i < G_N_ELEMENTS(good); i++) { + ck_assert_int_eq(0, oscar_util_name_compare("test", good[i])); + ck_assert_int_eq(0, oscar_util_name_compare(good[i], "test")); + } + for (i = 0; i < G_N_ELEMENTS(bad); i++) { + ck_assert_int_ne(0, oscar_util_name_compare("test", bad[i])); + ck_assert_int_ne(0, oscar_util_name_compare(bad[i], "test")); + } +} +END_TEST + +Suite *oscar_util_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("OSCAR Utility Functions"); + + tc = tcase_create("Convert IM from network format to HTML"); + tcase_add_test(tc, test_oscar_util_name_compare); + suite_add_tcase(s, tc); + + return s; +} diff -r a92f4cb593a4 -r 974722699032 libpurple/tests/test_util.c --- a/libpurple/tests/test_util.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/tests/test_util.c Mon Apr 25 20:13:05 2011 +0000 @@ -90,7 +90,9 @@ "a@singleLetterLocal.org", "singleLetterDomain@x.org", "&*=?^+{}'~@validCharsInLocal.net", - "foor@bar.newTLD" + "foor@bar.newTLD", + "HenryTheGreatWhiteCricket@live.ca", + "HenryThe__WhiteCricket@hotmail.com" }; const char *invalid_emails[] = { diff -r a92f4cb593a4 -r 974722699032 libpurple/tests/tests.h --- a/libpurple/tests/tests.h Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/tests/tests.h Mon Apr 25 20:13:05 2011 +0000 @@ -13,6 +13,7 @@ Suite * jabber_digest_md5_suite(void); Suite * jabber_jutil_suite(void); Suite * jabber_scram_suite(void); +Suite * oscar_util_suite(void); Suite * qq_suite(void); Suite * yahoo_util_suite(void); Suite * util_suite(void); diff -r a92f4cb593a4 -r 974722699032 libpurple/xmlnode.c --- a/libpurple/xmlnode.c Wed Feb 02 23:26:42 2011 +0000 +++ b/libpurple/xmlnode.c Mon Apr 25 20:13:05 2011 +0000 @@ -606,7 +606,7 @@ { struct _xmlnode_parser_data *xpd = user_data; - if(!element_name || !xpd->current || xpd->error) + if(!element_name || !xpd->current || xpd->error) return; if(xpd->current->parent) { diff -r a92f4cb593a4 -r 974722699032 pidgin/Makefile.am --- a/pidgin/Makefile.am Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/Makefile.am Mon Apr 25 20:13:05 2011 +0000 @@ -156,7 +156,6 @@ $(SM_LIBS) \ $(INTLLIBS) \ $(GTKSPELL_LIBS) \ - $(STARTUP_NOTIFICATION_LIBS) \ $(LIBXML_LIBS) \ $(GTK_LIBS) \ $(top_builddir)/libpurple/libpurple.la @@ -180,7 +179,6 @@ $(GTK_CFLAGS) \ $(DBUS_CFLAGS) \ $(GTKSPELL_CFLAGS) \ - $(STARTUP_NOTIFICATION_CFLAGS) \ $(LIBXML_CFLAGS) \ $(INTGG_CFLAGS) endif # ENABLE_GTK diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkaccount.c --- a/pidgin/gtkaccount.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkaccount.c Mon Apr 25 20:13:05 2011 +0000 @@ -143,6 +143,10 @@ GtkWidget *proxy_user_entry; GtkWidget *proxy_pass_entry; + /* Voice & Video Options*/ + GtkWidget *voice_frame; + GtkWidget *suppression_check; + } AccountPrefsDialog; static AccountsWindow *accounts_window = NULL; @@ -159,6 +163,7 @@ static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent); static void add_protocol_options(AccountPrefsDialog *dialog); static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent); +static void add_voice_options(AccountPrefsDialog *dialog); static const char * xmpp_default_domain_hackery(GtkWidget *protocol_combo) @@ -273,6 +278,7 @@ add_login_options(dialog, dialog->top_vbox); add_user_options(dialog, dialog->top_vbox); add_protocol_options(dialog); + add_voice_options(dialog); gtk_widget_grab_focus(dialog->protocol_menu); @@ -829,8 +835,11 @@ gtk_label_new_with_mnemonic(_("Ad_vanced")), 1); gtk_widget_show(vbox); +/* FIXME: Facebook forced-options hack */ +#if 0 menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu)); item = gtk_menu_get_active(GTK_MENU(menu)); +#endif for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next) { @@ -946,9 +955,12 @@ model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); opt_entry->widget = combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); +/* FIXME: Facebook forced-options hack */ +#if 0 if (g_object_get_data(G_OBJECT(item), "fakefacebook") && !strcmp(opt_entry->setting, "connection_security")) str_value = "opportunistic_tls"; +#endif /* Loop through list of PurpleKeyValuePair items */ for (node = list; node != NULL; node = node->next) { @@ -1191,6 +1203,39 @@ G_CALLBACK(proxy_type_changed_cb), dialog); } +static void +add_voice_options(AccountPrefsDialog *dialog) +{ +#ifdef USE_VV + if (!dialog->prpl_info || !PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(dialog->prpl_info, initiate_media)) { + if (dialog->voice_frame) { + gtk_widget_destroy(dialog->voice_frame); + dialog->voice_frame = NULL; + dialog->suppression_check = NULL; + } + return; + } + + if (!dialog->voice_frame) { + dialog->voice_frame = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); + gtk_container_set_border_width(GTK_CONTAINER(dialog->voice_frame), + PIDGIN_HIG_BORDER); + + dialog->suppression_check = + gtk_check_button_new_with_mnemonic(_("Use _silence suppression")); + gtk_box_pack_start(GTK_BOX(dialog->voice_frame), dialog->suppression_check, + FALSE, FALSE, 0); + + gtk_notebook_append_page(GTK_NOTEBOOK(dialog->notebook), + dialog->voice_frame, gtk_label_new_with_mnemonic(_("_Voice and Video"))); + gtk_widget_show_all(dialog->voice_frame); + } + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->suppression_check), + purple_account_get_silence_suppression(dialog->account)); +#endif +} + static gboolean account_win_destroy_cb(GtkWidget *w, GdkEvent *event, AccountPrefsDialog *dialog) @@ -1465,6 +1510,12 @@ proxy_info = NULL; } + /* Voice and Video settings */ + if (dialog->voice_frame) { + purple_account_set_silence_suppression(account, + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->suppression_check))); + } + /* If this is a new account, add it to our list */ if (new_acct) purple_accounts_add(account); @@ -1586,6 +1637,8 @@ gtk_widget_show(dbox); add_proxy_options(dialog, dbox); + add_voice_options(dialog); + /* Cancel button */ pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CANCEL, G_CALLBACK(cancel_account_prefs_cb), dialog); @@ -2174,7 +2227,6 @@ create_accounts_list(AccountsWindow *dialog) { GtkWidget *frame; - GtkWidget *sw; GtkWidget *label; GtkWidget *treeview; GtkTreeSelection *sel; @@ -2214,16 +2266,6 @@ gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5); gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook), label, NULL); - /* Create the scrolled window. */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_NONE); - gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook), sw, NULL); - gtk_widget_show(sw); - /* Create the list model. */ dialog->model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, /* COLUMN_ICON */ @@ -2249,7 +2291,9 @@ g_signal_connect(G_OBJECT(treeview), "button_press_event", G_CALLBACK(account_treeview_double_click_cb), dialog); - gtk_container_add(GTK_CONTAINER(sw), treeview); + gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook), + pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1), + NULL); add_columns(treeview, dialog); gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeview)); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkblist.c Mon Apr 25 20:13:05 2011 +0000 @@ -85,6 +85,7 @@ GtkWidget *combo; GtkWidget *entry; GtkWidget *entry_for_alias; + GtkWidget *entry_for_invite; } PidginAddBuddyData; @@ -461,9 +462,9 @@ GList *tmp; /* First, we find the contact to merge the rest of the buddies into. - * This will be the contact with the most buddies in it; ties are broken - * by which contact is higher in the list - */ + * This will be the contact with the most buddies in it; ties are broken + * by which contact is higher in the list + */ for (tmp = merges; tmp; tmp = tmp->next) { PurpleBlistNode *node = tmp->data; PurpleBlistNode *b; @@ -984,7 +985,7 @@ gtkblist = PIDGIN_BLIST(purple_get_blist()); blist_window = gtkblist ? GTK_WINDOW(gtkblist->window) : NULL; - /* TODO: set no separator in gtk+ 3... */ + /* TODO: set no separator in gtk+ 3... */ data->window = gtk_dialog_new_with_buttons(title, blist_window, 0, NULL); @@ -993,14 +994,14 @@ gtk_container_set_border_width(GTK_CONTAINER(data->window), PIDGIN_HIG_BOX_SPACE); gtk_window_set_resizable(GTK_WINDOW(data->window), FALSE); gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(data->window))), - PIDGIN_HIG_BORDER); + PIDGIN_HIG_BORDER); gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(data->window))), - PIDGIN_HIG_BOX_SPACE); + PIDGIN_HIG_BOX_SPACE); gtk_window_set_role(GTK_WINDOW(data->window), window_role); hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(data->window))), - hbox); + hbox); gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); gtk_misc_set_alignment(GTK_MISC(img), 0, 0); @@ -1559,7 +1560,7 @@ pidgin_append_blist_node_move_to_menu(menu, (PurpleBlistNode *)contact); if (node->parent && node->parent->child->next && - !sub && !contact_expanded) { + !sub && !contact_expanded) { pidgin_separator(menu); pidgin_append_blist_node_privacy_menu(menu, node); pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, @@ -1746,8 +1747,7 @@ gboolean autojoin, persistent; menu = gtk_menu_new(); - autojoin = (purple_blist_node_get_bool(node, "gtk-autojoin") || - (purple_blist_node_get_string(node, "gtk-autojoin") != NULL)); + autojoin = purple_blist_node_get_bool(node, "gtk-autojoin"); persistent = purple_blist_node_get_bool(node, "gtk-persistent"); pidgin_new_item_from_stock(menu, _("_Join"), PIDGIN_STOCK_CHAT, @@ -2250,7 +2250,7 @@ guint time, gpointer null) { - GdkAtom target = gtk_selection_data_get_target(data); + GdkAtom target = gtk_selection_data_get_target(data); if (target == gdk_atom_intern("PURPLE_BLIST_NODE", FALSE)) { GtkTreeRowReference *ref = g_object_get_data(G_OBJECT(dc), "gtk-tree-view-source-row"); @@ -2346,8 +2346,8 @@ static void pidgin_blist_drag_data_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t) { - GdkAtom target = gtk_selection_data_get_target(sd); - const guchar *data = gtk_selection_data_get_data(sd); + GdkAtom target = gtk_selection_data_get_target(sd); + const guchar *data = gtk_selection_data_get_data(sd); if (gtkblist->drag_timeout) { g_source_remove(gtkblist->drag_timeout); @@ -2557,7 +2557,7 @@ gtk_tree_path_free(path); gtk_drag_finish(dc, TRUE, - (gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE), t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } else if (target == gdk_atom_intern("text/x-vcard", FALSE) && data) { @@ -2595,7 +2595,7 @@ result = parse_vcard((const gchar *) data, group); gtk_drag_finish(dc, result, - (gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE), t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } else if (target == gdk_atom_intern("text/uri-list", FALSE) && data) { GtkTreePath *path = NULL; GtkTreeViewDropPosition position; @@ -2615,7 +2615,7 @@ PurpleBuddy *b = PURPLE_BLIST_NODE_IS_BUDDY(node) ? PURPLE_BUDDY(node) : purple_contact_get_priority_buddy(PURPLE_CONTACT(node)); pidgin_dnd_file_manage(sd, b->account, b->name); gtk_drag_finish(dc, TRUE, - (gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE), t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } else { gtk_drag_finish(dc, FALSE, FALSE, t); } @@ -2979,56 +2979,57 @@ for(l = gtkblist->tooltipdata; l; l = l->next) { struct tooltip_data *td = l->data; - cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(gtkblist->tipwindow)); + cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(gtkblist->tipwindow)); if (td->avatar && pidgin_gdk_pixbuf_is_opaque(td->avatar)) { if (dir == GTK_TEXT_DIR_RTL) gtk_paint_flat_box(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_OUT, gtkblist->tipwindow, "tooltip", - TOOLTIP_BORDER -1, current_height -1, td->avatar_width +2, - td->avatar_height + 2); + TOOLTIP_BORDER - 1, current_height - 1, + td->avatar_width + 2, td->avatar_height + 2); else gtk_paint_flat_box(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_OUT, gtkblist->tipwindow, "tooltip", - max_width - (td->avatar_width+ TOOLTIP_BORDER)-1, - current_height-1,td->avatar_width+2, td->avatar_height+2); + max_width - (td->avatar_width + TOOLTIP_BORDER) - 1, + current_height - 1, + td->avatar_width + 2, td->avatar_height + 2); } if (td->status_icon) { if (dir == GTK_TEXT_DIR_RTL) { - gdk_cairo_set_source_pixbuf(cr, td->status_icon, - max_width - TOOLTIP_BORDER - status_size, current_height); - cairo_paint(cr); - } else { - gdk_cairo_set_source_pixbuf(cr, td->status_icon, TOOLTIP_BORDER, current_height); - cairo_paint(cr); - } - } + gdk_cairo_set_source_pixbuf(cr, td->status_icon, + max_width - TOOLTIP_BORDER - status_size, current_height); + cairo_paint(cr); + } else { + gdk_cairo_set_source_pixbuf(cr, td->status_icon, TOOLTIP_BORDER, current_height); + cairo_paint(cr); + } + } if (td->avatar) { if (dir == GTK_TEXT_DIR_RTL) { - gdk_cairo_set_source_pixbuf(cr, td->avatar, TOOLTIP_BORDER, - current_height); - cairo_paint(cr); - } else { - gdk_cairo_set_source_pixbuf(cr, td->avatar, - max_width - (td->avatar_width + TOOLTIP_BORDER), current_height); - cairo_paint(cr); - } + gdk_cairo_set_source_pixbuf(cr, td->avatar, TOOLTIP_BORDER, + current_height); + cairo_paint(cr); + } else { + gdk_cairo_set_source_pixbuf(cr, td->avatar, + max_width - (td->avatar_width + TOOLTIP_BORDER), current_height); + cairo_paint(cr); + } } if (!td->avatar_is_prpl_icon && td->prpl_icon) { - gdk_cairo_set_source_pixbuf(cr, td->prpl_icon, prpl_col, - current_height + ((td->name_height / 2) - (PRPL_SIZE / 2))); - cairo_paint(cr); - } + gdk_cairo_set_source_pixbuf(cr, td->prpl_icon, prpl_col, + current_height + ((td->name_height / 2) - (PRPL_SIZE / 2))); + cairo_paint(cr); + } if (td->name_layout) { if (dir == GTK_TEXT_DIR_RTL) { gtk_paint_layout(style, cr, GTK_STATE_NORMAL, FALSE, gtkblist->tipwindow, "tooltip", - max_width -(TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000), + max_width - (TOOLTIP_BORDER + status_size + SMALL_SPACE) - PANGO_PIXELS(300000), current_height, td->name_layout); } else { gtk_paint_layout (style, cr, GTK_STATE_NORMAL, FALSE, @@ -3051,7 +3052,7 @@ } } - cairo_destroy(cr); + cairo_destroy(cr); current_height += MAX(td->name_height + td->height, td->avatar_height) + td->padding; } return FALSE; @@ -3600,11 +3601,11 @@ } purple_request_fields(gc, _("Edit User Mood"), _("Edit User Mood"), - NULL, fields, - _("OK"), G_CALLBACK(edit_mood_cb), - _("Cancel"), NULL, - gc ? purple_connection_get_account(gc) : NULL, - NULL, NULL, gc); + NULL, fields, + _("OK"), G_CALLBACK(edit_mood_cb), + _("Cancel"), NULL, + gc ? purple_connection_get_account(gc) : NULL, + NULL, NULL, gc); g_free(global_moods); } @@ -5899,7 +5900,6 @@ GtkTreeViewColumn *column; GtkWidget *menu; GtkWidget *ebox; - GtkWidget *sw; GtkWidget *sep; GtkWidget *label; GtkWidget *close; @@ -5943,7 +5943,7 @@ g_signal_connect(G_OBJECT(gtkblist->window), "focus-out-event", G_CALLBACK(blist_focus_cb), gtkblist); - /* TODO: how is this done in gtk+ 3.0? */ + /* TODO: how is this done in gtk+ 3.0? */ /*GTK_WINDOW(gtkblist->window)->allow_shrink = TRUE;*/ gtkblist->main_vbox = gtk_vbox_new(FALSE, 0); @@ -6029,10 +6029,8 @@ gtk_container_set_border_width(GTK_CONTAINER(gtkblist->headline_hbox), 6); gtk_container_add(GTK_CONTAINER(ebox), gtkblist->headline_hbox); gtkblist->headline_image = gtk_image_new_from_pixbuf(NULL); - gtk_misc_set_alignment(GTK_MISC(gtkblist->headline_image), 0.0, 0); + gtk_misc_set_alignment(GTK_MISC(gtkblist->headline_image), 0.5, 0.5); gtkblist->headline_label = gtk_label_new(NULL); - gtk_widget_set_size_request(gtkblist->headline_label, - purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width")-25,-1); gtk_label_set_line_wrap(GTK_LABEL(gtkblist->headline_label), TRUE); gtk_box_pack_start(GTK_BOX(gtkblist->headline_hbox), gtkblist->headline_image, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(gtkblist->headline_hbox), gtkblist->headline_label, TRUE, TRUE, 0); @@ -6066,11 +6064,6 @@ g_signal_connect(G_OBJECT(ebox), "button-press-event", G_CALLBACK(headline_box_press_cb), gtkblist); /****************************** GtkTreeView **********************************/ - sw = gtk_scrolled_window_new(NULL,NULL); - gtk_widget_show(sw); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_NONE); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtkblist->treemodel = gtk_tree_store_new(BLIST_COLUMNS, GDK_TYPE_PIXBUF, /* Status icon */ G_TYPE_BOOLEAN, /* Status icon visible */ @@ -6150,8 +6143,9 @@ gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(gtkblist->treeview), pidgin_blist_search_equal_func, NULL, NULL); - gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sw, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(sw), gtkblist->treeview); + gtk_box_pack_start(GTK_BOX(gtkblist->vbox), + pidgin_make_scrollable(gtkblist->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1), + TRUE, TRUE, 0); sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(gtkblist->vbox), sep, FALSE, FALSE, 0); @@ -7103,7 +7097,7 @@ if (show) { if(!PIDGIN_WINDOW_ICONIFIED(gtkblist->window) && - !gtk_widget_get_visible(gtkblist->window)) + !gtk_widget_get_visible(gtkblist->window)) purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-unhiding", gtkblist); pidgin_blist_restore_position(); gtk_window_present(GTK_WINDOW(gtkblist->window)); @@ -7156,8 +7150,24 @@ add_buddy_select_account_cb(GObject *w, PurpleAccount *account, PidginAddBuddyData *data) { + PurpleConnection *pc = NULL; + PurplePlugin *prpl = NULL; + PurplePluginProtocolInfo *prpl_info = NULL; + gboolean invite_enabled = TRUE; + /* Save our account */ data->rq_data.account = account; + + if (account) + pc = purple_account_get_connection(account); + if (pc) + prpl = purple_connection_get_prpl(pc); + if (prpl) + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + if (prpl_info && !(prpl_info->options & OPT_PROTO_INVITE_MESSAGE)) + invite_enabled = FALSE; + + gtk_widget_set_sensitive(data->entry_for_invite, invite_enabled); } static void @@ -7169,7 +7179,7 @@ static void add_buddy_cb(GtkWidget *w, int resp, PidginAddBuddyData *data) { - const char *grp, *who, *whoalias; + const char *grp, *who, *whoalias, *invite; PurpleAccount *account; PurpleGroup *g; PurpleBuddy *b; @@ -7183,6 +7193,9 @@ whoalias = gtk_entry_get_text(GTK_ENTRY(data->entry_for_alias)); if (*whoalias == '\0') whoalias = NULL; + invite = gtk_entry_get_text(GTK_ENTRY(data->entry_for_invite)); + if (*invite == '\0') + invite = NULL; account = data->rq_data.account; @@ -7208,7 +7221,7 @@ purple_blist_add_buddy(b, NULL, g, NULL); } - purple_account_add_buddy(account, b); + purple_account_add_buddy_with_invite(account, b, invite); /* Offer to merge people with the same alias. */ if (whoalias != NULL && g != NULL) @@ -7246,9 +7259,11 @@ { PidginAddBuddyData *data = g_new0(PidginAddBuddyData, 1); + if (account == NULL) + account = purple_connection_get_account(purple_connections_get_all()->data); + make_blist_request_dialog((PidginBlistRequestData *)data, - (account != NULL - ? account : purple_connection_get_account(purple_connections_get_all()->data)), + account, _("Add Buddy"), "add_buddy", _("Add a buddy.\n"), G_CALLBACK(add_buddy_select_account_cb), NULL, @@ -7292,11 +7307,19 @@ if (username != NULL) gtk_widget_grab_focus(GTK_WIDGET(data->entry_for_alias)); + data->entry_for_invite = gtk_entry_new(); + pidgin_add_widget_to_vbox(data->rq_data.vbox, _("(Optional) _Invite message:"), + data->rq_data.sg, data->entry_for_invite, TRUE, + NULL); + data->combo = pidgin_text_combo_box_entry_new(group, groups_tree()); pidgin_add_widget_to_vbox(data->rq_data.vbox, _("Add buddy to _group:"), data->rq_data.sg, data->combo, TRUE, NULL); gtk_widget_show_all(data->rq_data.window); + + /* Force update of invite message entry sensitivity */ + add_buddy_select_account_cb(NULL, account, data); } static void @@ -7607,9 +7630,7 @@ if(chat->account != account) continue; - if(purple_blist_node_get_bool((PurpleBlistNode*)chat, "gtk-autojoin") || - (purple_blist_node_get_string((PurpleBlistNode*)chat, - "gtk-autojoin") != NULL)) + if (purple_blist_node_get_bool((PurpleBlistNode*)chat, "gtk-autojoin")) serv_join_chat(gc, chat->components); } } @@ -7930,7 +7951,7 @@ gtk_tree_store_append(gtkblist->treemodel, iter, &groupiter); return; } else { - sort_method_none(node, blist, groupiter, cur, iter); + sort_method_alphabetical(node, blist, groupiter, cur, iter); return; } @@ -8047,7 +8068,7 @@ if(PURPLE_BLIST_NODE_IS_CONTACT(n)) { for (n2 = n->child; n2; n2 = n2->next) { - buddy = (PurpleBuddy*)n2; + buddy = (PurpleBuddy*)n2; this_log_activity_score += purple_log_get_activity_score(PURPLE_LOG_IM, buddy->name, buddy->account); } this_buddy_name = purple_contact_get_alias((PurpleContact*)n); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkcertmgr.c --- a/pidgin/gtkcertmgr.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkcertmgr.c Mon Apr 25 20:13:05 2011 +0000 @@ -390,7 +390,6 @@ { GtkWidget *bbox; GtkListStore *store; - GtkWidget *sw; /* This block of variables will end up in tpm_dat */ GtkTreeView *listview; @@ -417,16 +416,6 @@ g_signal_connect(G_OBJECT(mgmt_widget), "destroy", G_CALLBACK(tls_peers_mgmt_destroy), NULL); - /* Scrolled window */ - sw = gtk_scrolled_window_new(NULL,NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(mgmt_widget), GTK_WIDGET(sw), - TRUE, TRUE, /* Take up lots of space */ - 0); - gtk_widget_show(GTK_WIDGET(sw)); - /* List view */ store = gtk_list_store_new(TPM_N_COLUMNS, G_TYPE_STRING); @@ -463,7 +452,10 @@ g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(tls_peers_mgmt_select_chg_cb), NULL); - gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(listview)); + gtk_box_pack_start(GTK_BOX(mgmt_widget), + pidgin_make_scrollable(GTK_WIDGET(listview), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, /* Take up lots of space */ + 0); gtk_widget_show(GTK_WIDGET(listview)); /* Fill the list for the first time */ diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkconv.c Mon Apr 25 20:13:05 2011 +0000 @@ -78,9 +78,9 @@ #define AUTO_RESPONSE "<AUTO-REPLY> : " -typedef enum -{ - PIDGIN_CONV_SET_TITLE = 1 << 0, +typedef enum +{ + PIDGIN_CONV_SET_TITLE = 1 << 0, PIDGIN_CONV_BUDDY_ICON = 1 << 1, PIDGIN_CONV_MENU = 1 << 2, PIDGIN_CONV_TAB_ICON = 1 << 3, @@ -141,8 +141,6 @@ static GList *away_list = NULL; static GList *busy_list = NULL; static GList *xa_list = NULL; -static GList *login_list = NULL; -static GList *logout_list = NULL; static GList *offline_list = NULL; static GHashTable *prpl_lists = NULL; @@ -778,16 +776,16 @@ InviteBuddyInfo *info = (InviteBuddyInfo *)data; const char *convprotocol; gboolean success = TRUE; - GdkAtom target = gtk_selection_data_get_target(sd); - + GdkAtom target = gtk_selection_data_get_target(sd); + convprotocol = purple_account_get_protocol_id(purple_conversation_get_account(info->conv)); if (target == gdk_atom_intern("PURPLE_BLIST_NODE", FALSE)) { PurpleBlistNode *node = NULL; PurpleBuddy *buddy; - const guchar *data = gtk_selection_data_get_data(sd); - + const guchar *data = gtk_selection_data_get_data(sd); + memcpy(&node, data, sizeof(node)); if (PURPLE_BLIST_NODE_IS_CONTACT(node)) @@ -808,7 +806,7 @@ gtk_entry_set_text(GTK_ENTRY(info->entry), purple_buddy_get_name(buddy)); gtk_drag_finish(dc, success, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } else if (target == gdk_atom_intern("application/x-im-contact", FALSE)) { @@ -842,7 +840,7 @@ g_free(protocol); gtk_drag_finish(dc, success, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } } @@ -884,11 +882,11 @@ GTK_RESPONSE_OK); gtk_container_set_border_width(GTK_CONTAINER(invite_dialog), PIDGIN_HIG_BOX_SPACE); gtk_window_set_resizable(GTK_WINDOW(invite_dialog), FALSE); - /* TODO: set no separator using GTK+ 3.0 */ - /* + /* TODO: set no separator using GTK+ 3.0 */ +#if 0 gtk_dialog_set_has_separator(GTK_DIALOG(invite_dialog), FALSE); - */ - +#endif + info->window = GTK_WIDGET(invite_dialog); /* Setup the outside spacing. */ @@ -2200,7 +2198,7 @@ (event->keyval == GDK_KEY_Left) || (event->keyval == GDK_KEY_Right) || (event->keyval == GDK_KEY_Page_Up) || - (event->keyval == GDK_KEY_KP_Page_Up) || + (event->keyval == GDK_KEY_KP_Page_Up) || (event->keyval == GDK_KEY_Page_Down) || (event->keyval == GDK_KEY_KP_Page_Down) || (event->keyval == GDK_KEY_Home) || @@ -2438,8 +2436,7 @@ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { PurpleBuddy *b = purple_find_buddy(account, name); if (b != NULL) { - PurplePresence *p; - p = purple_buddy_get_presence(b); + PurplePresence *p = purple_buddy_get_presence(b); if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY)) return away_list; if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE)) @@ -3081,7 +3078,7 @@ { "MediaMenu", NULL, N_("M_edia"), NULL, NULL, NULL }, { "AudioCall", PIDGIN_STOCK_TOOLBAR_AUDIO_CALL, N_("_Audio Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) }, { "VideoCall", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL, N_("_Video Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) }, - { "AudioVideoCall", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL, N_("Audio\\/Video _Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) }, + { "AudioVideoCall", PIDGIN_STOCK_TOOLBAR_VIDEO_CALL, N_("Audio/Video _Call"), NULL, NULL, G_CALLBACK(menu_initiate_media_call_cb) }, #endif { "SendFile", PIDGIN_STOCK_TOOLBAR_SEND_FILE, N_("Se_nd File..."), NULL, NULL, G_CALLBACK(menu_send_file_cb) }, @@ -3411,14 +3408,21 @@ static void regenerate_options_items(PidginWindow *win) { -#if GTK_CHECK_VERSION(2,6,0) -#else GtkWidget *menu; PidginConversation *gtkconv; GList *list; +#if GTK_CHECK_VERSION(2,6,0) + GtkWidget *more_menu; gtkconv = pidgin_conv_window_get_active_gtkconv(win); + more_menu = gtk_ui_manager_get_widget(win->menu.ui, + "/Conversation/ConversationMenu/MoreMenu"); + gtk_widget_show(more_menu); + menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(more_menu)); +#else + gtkconv = pidgin_conv_window_get_active_gtkconv(win); menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Conversation/More")); +#endif /* Remove the previous entries */ for (list = gtk_container_get_children(GTK_CONTAINER(menu)); list; ) @@ -3436,7 +3440,6 @@ } gtk_widget_show_all(menu); -#endif } static void @@ -3450,8 +3453,6 @@ static void regenerate_plugins_items(PidginWindow *win) { -#if GTK_CHECK_VERSION(2,6,0) -#else GList *action_items; GtkWidget *menu; GList *list; @@ -3477,7 +3478,12 @@ action_items = g_list_delete_link(action_items, action_items); } +#if GTK_CHECK_VERSION(2,6,0) + item = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/OptionsMenu"); + menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item)); +#else menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Options")); +#endif list = purple_conversation_get_extended_menu(conv); if (list) { @@ -3493,10 +3499,8 @@ g_signal_connect(G_OBJECT(item), "destroy", G_CALLBACK(remove_from_list), win); } g_object_set_data(G_OBJECT(win->window), "plugin-actions", action_items); -#endif -} - -#if 0 +} + static void menubar_activated(GtkWidget *item, gpointer data) { PidginWindow *win = data; @@ -3515,12 +3519,11 @@ { /* The menubar has been deactivated. Make sure the 'More' submenu is regenerated next time * the 'Conversation' menu pops up. */ - GtkWidget *menuitem = gtk_item_factory_get_item(win->menu.item_factory, N_("/Conversation")); + GtkWidget *menuitem = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/ConversationMenu"); g_signal_handlers_unblock_by_func(G_OBJECT(menuitem), G_CALLBACK(menubar_activated), win); g_signal_handlers_disconnect_by_func(G_OBJECT(win->menu.menubar), G_CALLBACK(focus_out_from_menubar), win); } -#endif static GtkWidget * setup_menubar(PidginWindow *win) @@ -3529,6 +3532,7 @@ const char *method; GtkActionGroup *action_group; GError *error; + GtkWidget *menuitem; action_group = gtk_action_group_new("ConversationActions"); gtk_action_group_add_actions(action_group, @@ -3563,6 +3567,9 @@ win->menu.menubar = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation"); + menuitem = gtk_ui_manager_get_widget(win->menu.ui, "/Conversation/ConversationMenu"); + g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menubar_activated), win); + win->menu.view_log = gtk_ui_manager_get_action(win->menu.ui, "/Conversation/ConversationMenu/ViewLog"); @@ -3733,10 +3740,10 @@ break; } if (gtkwin->menu.typing_icon == NULL) { - gtkwin->menu.typing_icon = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_MENU); - pidgin_menu_tray_append(PIDGIN_MENU_TRAY(gtkwin->menu.tray), - gtkwin->menu.typing_icon, - _("User is typing...")); + gtkwin->menu.typing_icon = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_MENU); + pidgin_menu_tray_append(PIDGIN_MENU_TRAY(gtkwin->menu.tray), + gtkwin->menu.typing_icon, + _("User is typing...")); } else { gtk_image_set_from_stock(GTK_IMAGE(gtkwin->menu.typing_icon), stock_id, GTK_ICON_SIZE_MENU); } @@ -4684,13 +4691,13 @@ GtkAllocation imhtml_allocation; GtkAllocation entry_allocation; GtkAllocation lower_hbox_allocation; - + gtk_widget_get_allocation(gtkconv->imhtml, &imhtml_allocation); gtk_widget_get_allocation(gtkconv->entry, &entry_allocation); gtk_widget_get_allocation(gtkconv->lower_hbox, &lower_hbox_allocation); total_height = imhtml_allocation.height + entry_allocation.height; max_height = total_height / 2; - + pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(gtkconv->entry)); pad_bottom = gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(gtkconv->entry)); pad_inside = gtk_text_view_get_pixels_inside_wrap(GTK_TEXT_VIEW(gtkconv->entry)); @@ -4822,7 +4829,7 @@ setup_chat_userlist(PidginConversation *gtkconv, GtkWidget *hpaned) { PidginChatPane *gtkchat = gtkconv->u.chat; - GtkWidget *lbox, *sw, *list; + GtkWidget *lbox, *list; GtkListStore *ls; GtkCellRenderer *rend; GtkTreeViewColumn *col; @@ -4842,12 +4849,6 @@ gtk_widget_show(gtkchat->count); /* Setup the list of users. */ - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(lbox), sw, TRUE, TRUE, 0); - gtk_widget_show(sw); ls = gtk_list_store_new(CHAT_USERS_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, @@ -4917,7 +4918,9 @@ gtkchat->list = list; - gtk_container_add(GTK_CONTAINER(sw), list); + gtk_box_pack_start(GTK_BOX(lbox), + pidgin_make_scrollable(list, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 0); } static gboolean @@ -5028,7 +5031,6 @@ PurpleConversation *conv = gtkconv->active_conv; PurpleBuddy *buddy; gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT); - GtkPolicyType imhtml_sw_hscroll; int buddyicon_size = 0; /* Setup the top part of the pane */ @@ -5145,10 +5147,7 @@ gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),TRUE); g_object_set_data(G_OBJECT(gtkconv->imhtml), "gtkconv", gtkconv); - gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(imhtml_sw), - &imhtml_sw_hscroll, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw), - imhtml_sw_hscroll, GTK_POLICY_ALWAYS); + g_object_set(G_OBJECT(imhtml_sw), "vscrollbar-policy", GTK_POLICY_ALWAYS, NULL); g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event", G_CALLBACK(entry_stop_rclick_cb), NULL); @@ -5218,9 +5217,9 @@ PurpleAccount *convaccount = purple_conversation_get_account(conv); PurpleConnection *gc = purple_account_get_connection(convaccount); PurplePluginProtocolInfo *prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL; - GdkAtom target = gtk_selection_data_get_target(sd); - const guchar *data = gtk_selection_data_get_data(sd); - + GdkAtom target = gtk_selection_data_get_target(sd); + const guchar *data = gtk_selection_data_get_data(sd); + if (target == gdk_atom_intern("PURPLE_BLIST_NODE", FALSE)) { PurpleBlistNode *n = NULL; @@ -5278,7 +5277,7 @@ } gtk_drag_finish(dc, TRUE, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } else if (target == gdk_atom_intern("application/x-im-contact", FALSE)) { @@ -5319,13 +5318,13 @@ g_free(protocol); gtk_drag_finish(dc, TRUE, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } else if (target == gdk_atom_intern("text/uri-list", FALSE)) { if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) pidgin_dnd_file_manage(sd, convaccount, purple_conversation_get_name(conv)); gtk_drag_finish(dc, TRUE, - gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); + gdk_drag_context_get_actions(dc) == GDK_ACTION_MOVE, t); } else gtk_drag_finish(dc, FALSE, FALSE, t); @@ -5731,31 +5730,26 @@ GdkEventButton *btn_event = (GdkEventButton*) event; PurpleConversation *conv = data; char *buddyname; - gchar *name; - - g_object_get(G_OBJECT(tag), "name", &name, NULL); - + gchar *name; + + g_object_get(G_OBJECT(tag), "name", &name, NULL); + /* strlen("BUDDY " or "HILIT ") == 6 */ g_return_val_if_fail((name != NULL) && (strlen(name) > 6), FALSE); buddyname = name + 6; - - if (btn_event->button == 1 && - event->type == GDK_2BUTTON_PRESS) { + if (btn_event->button == 1 && event->type == GDK_2BUTTON_PRESS) { chat_do_im(PIDGIN_CONVERSATION(conv), buddyname); - g_free(name); + g_free(name); return TRUE; - } else if (btn_event->button == 2 - && event->type == GDK_2BUTTON_PRESS) { + } else if (btn_event->button == 2 && event->type == GDK_2BUTTON_PRESS) { chat_do_info(PIDGIN_CONVERSATION(conv), buddyname); - - g_free(name); - + g_free(name); + return TRUE; - } else if (btn_event->button == 3 - && event->type == GDK_BUTTON_PRESS) { + } else if (btn_event->button == 3 && event->type == GDK_BUTTON_PRESS) { GtkTextIter start, end; /* we shouldn't display the popup @@ -5774,14 +5768,14 @@ btn_event->button, btn_event->time); - g_free(name); - + g_free(name); + /* Don't propagate the event any further */ return TRUE; } } - g_free(name); + g_free(name); } return FALSE; @@ -6278,7 +6272,7 @@ /* Currently GTK+ maintains our sorted list after it's in the tree. * This may change if it turns out we can manage it faster ourselves. - */ + */ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), CHAT_USERS_ALIAS_KEY_COLUMN, GTK_SORT_ASCENDING); } @@ -6630,13 +6624,13 @@ gtk_action_set_visible(win->menu.get_info, TRUE); gtk_action_set_visible(win->menu.invite, FALSE); gtk_action_set_visible(win->menu.alias, TRUE); - if (purple_privacy_check(account, purple_conversation_get_name(conv))) { - gtk_action_set_visible(win->menu.unblock, FALSE); - gtk_action_set_visible(win->menu.block, TRUE); - } else { - gtk_action_set_visible(win->menu.block, FALSE); - gtk_action_set_visible(win->menu.unblock, TRUE); - } + if (purple_privacy_check(account, purple_conversation_get_name(conv))) { + gtk_action_set_visible(win->menu.unblock, FALSE); + gtk_action_set_visible(win->menu.block, TRUE); + } else { + gtk_action_set_visible(win->menu.block, FALSE); + gtk_action_set_visible(win->menu.unblock, TRUE); + } if ((account == NULL) || purple_find_buddy(account, purple_conversation_get_name(conv)) == NULL) { gtk_action_set_visible(win->menu.add, TRUE); @@ -6857,12 +6851,12 @@ if ((fields & PIDGIN_CONV_COLORIZE_TITLE) || (fields & PIDGIN_CONV_SET_TITLE) || - (fields & PIDGIN_CONV_TOPIC)) + (fields & PIDGIN_CONV_TOPIC)) { char *title; PurpleConvIm *im = NULL; PurpleAccount *account = purple_conversation_get_account(conv); - PurpleBuddy *buddy = NULL; + PurpleBuddy *buddy = NULL; char *markup = NULL; AtkObject *accessibility_obj; /* I think this is a little longer than it needs to be but I'm lazy. */ @@ -6933,7 +6927,7 @@ atk_object_set_description(accessibility_obj, _("New Event")); style = "tab-label-event"; } else { - style = NULL; + style = "tab-label"; } gtk_widget_set_name(gtkconv->tab_label, style); @@ -7241,7 +7235,7 @@ gtk_container_add(GTK_CONTAINER(gtkconv->u.im->icon_container), event); gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), FALSE); gtk_widget_add_events(event, - GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); + GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(event), "button-press-event", G_CALLBACK(icon_menu), gtkconv); @@ -7283,13 +7277,13 @@ { gint pane_x, pane_y, x_rel; PidginConversation *gtkconv; - GtkAllocation allocation; - - gtk_widget_get_allocation(gtkconv->infopane, &allocation); + GtkAllocation allocation; + gdk_window_get_origin(gtk_widget_get_window(win->notebook), - &pane_x, &pane_y); + &pane_x, &pane_y); x_rel = x - pane_x; gtkconv = pidgin_conv_window_get_active_gtkconv(win); + gtk_widget_get_allocation(gtkconv->infopane, &allocation); return (x_rel > allocation.x + allocation.width / 2); } @@ -7318,7 +7312,7 @@ count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook)); for (i = 0; i < count; i++) { - GtkAllocation allocation; + GtkAllocation allocation; page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), i); tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(notebook), page); @@ -7728,33 +7722,11 @@ } } -struct _status_timeout_user { - gchar *name; - PurpleAccount *account; -}; - -static gboolean -update_buddy_status_timeout(struct _status_timeout_user *user) -{ - /* To remove the signing-on/off door icon */ - PurpleConversation *conv; - - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, user->name, user->account); - if (conv) - pidgin_conv_update_fields(conv, PIDGIN_CONV_TAB_ICON); - - g_free(user->name); - g_free(user); - - return FALSE; -} - static void update_buddy_status_changed(PurpleBuddy *buddy, PurpleStatus *old, PurpleStatus *newstatus) { PidginConversation *gtkconv; PurpleConversation *conv; - struct _status_timeout_user *user; gtkconv = get_gtkconv_with_contact(purple_buddy_get_contact(buddy)); if (gtkconv) @@ -7766,13 +7738,6 @@ if ((purple_status_is_online(old) ^ purple_status_is_online(newstatus)) != 0) pidgin_conv_update_fields(conv, PIDGIN_CONV_MENU); } - - user = g_malloc(sizeof(struct _status_timeout_user)); - user->name = g_strdup(buddy->name); - user->account = buddy->account; - - /* In case a conversation is started after the buddy has signed-on/off */ - purple_timeout_add_seconds(11, (GSourceFunc)update_buddy_status_timeout, user); } static void @@ -8112,7 +8077,7 @@ purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/blist/show_protocol_icons", show_protocol_icons_pref_cb, NULL); purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/im/hide_new", - hide_new_pref_cb, NULL); + hide_new_pref_cb, NULL); @@ -8249,7 +8214,7 @@ window_list = g_list_remove(window_list, hidden_convwin); purple_signal_connect(purple_accounts_get_handle(), "account-status-changed", - handle, PURPLE_CALLBACK(account_status_changed_cb), NULL); + handle, PURPLE_CALLBACK(account_status_changed_cb), NULL); /* Callbacks to update a conversation */ purple_signal_connect(blist_handle, "blist-node-added", handle, @@ -8434,12 +8399,12 @@ 6); gtk_window_set_resizable(GTK_WINDOW(warn_close_dialog), FALSE); - /* TODO: figure out how to set no separator in GTK+ 3.0 */ - /* - gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog), + /* TODO: figure out how to set no separator in GTK+ 3.0 */ +#if 0 + gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog), FALSE); - */ - +#endif + /* Setup the outside spacing. */ vbox = gtk_dialog_get_content_area(GTK_DIALOG(warn_close_dialog)); @@ -8715,10 +8680,10 @@ if (e->button == 1) { int nb_x, nb_y; - GtkAllocation allocation; - - gtk_widget_get_allocation(gtkconv->infopane_hbox, &allocation); - + GtkAllocation allocation; + + gtk_widget_get_allocation(gtkconv->infopane_hbox, &allocation); + if (gtkconv->win->in_drag) return TRUE; @@ -8773,7 +8738,7 @@ int tab_clicked; GtkWidget *page; GtkWidget *tab; - GtkAllocation allocation; + GtkAllocation allocation; if (e->button == 2 && e->type == GDK_BUTTON_PRESS) { PidginConversation *gtkconv; @@ -8823,7 +8788,7 @@ page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), tab_clicked); tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(win->notebook), page); - gtk_widget_get_allocation(tab, &allocation); + gtk_widget_get_allocation(tab, &allocation); win->drag_min_x = allocation.x + nb_x; win->drag_min_y = allocation.y + nb_y; @@ -8836,8 +8801,8 @@ e->y_root < win->drag_min_y || e->y_root >= win->drag_max_y) { - return FALSE; - } + return FALSE; + } win->in_predrag = TRUE; win->drag_tab = tab_clicked; @@ -9072,8 +9037,8 @@ { GtkWidget *item; PidginConversation *gtkconv; - GtkWidget *menu = gtk_notebook_get_menu - + GtkWidget *menu = gtk_notebook_get_menu + if (event->type != GDK_BUTTON_PRESS || event->button != 3) return FALSE; @@ -9168,8 +9133,7 @@ PurpleBuddy *buddy; buddy = purple_find_buddy(account, name); if (buddy != NULL) { - purple_blist_alias_buddy(buddy, - gtk_entry_get_text(entry)); + purple_blist_alias_buddy(buddy, gtk_entry_get_text(entry)); } serv_alias_buddy(buddy); } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { @@ -9315,14 +9279,18 @@ make_status_icon_list(const char *stock, GtkWidget *w) { GList *l = NULL; - l = g_list_append(l, gtk_widget_render_icon (w, stock, - gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL), "GtkWindow")); - l = g_list_append(l, gtk_widget_render_icon (w, stock, - gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL), "GtkWindow")); - l = g_list_append(l, gtk_widget_render_icon (w, stock, - gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MEDIUM), "GtkWindow")); - l = g_list_append(l, gtk_widget_render_icon (w, stock, - gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_LARGE), "GtkWindow")); + l = g_list_append(l, + gtk_widget_render_icon(w, stock, + gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL), "GtkWindow")); + l = g_list_append(l, + gtk_widget_render_icon(w, stock, + gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL), "GtkWindow")); + l = g_list_append(l, + gtk_widget_render_icon(w, stock, + gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MEDIUM), "GtkWindow")); + l = g_list_append(l, + gtk_widget_render_icon(w, stock, + gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_LARGE), "GtkWindow")); return l; } @@ -9332,8 +9300,6 @@ available_list = make_status_icon_list(PIDGIN_STOCK_STATUS_AVAILABLE, w); busy_list = make_status_icon_list(PIDGIN_STOCK_STATUS_BUSY, w); xa_list = make_status_icon_list(PIDGIN_STOCK_STATUS_XA, w); - login_list = make_status_icon_list(PIDGIN_STOCK_STATUS_LOGIN, w); - logout_list = make_status_icon_list(PIDGIN_STOCK_STATUS_LOGOUT, w); offline_list = make_status_icon_list(PIDGIN_STOCK_STATUS_OFFLINE, w); away_list = make_status_icon_list(PIDGIN_STOCK_STATUS_AWAY, w); prpl_lists = g_hash_table_new(g_str_hash, g_str_equal); @@ -9380,8 +9346,8 @@ pidgin_conv_set_position_size(PidginWindow *win, int conv_x, int conv_y, int conv_width, int conv_height) { - /* if the window exists, is hidden, we're saving positions, and the - * position is sane... */ + /* if the window exists, is hidden, we're saving positions, and the + * position is sane... */ if (win && win->window && !gtk_widget_get_visible(win->window) && conv_width != 0) { @@ -9468,13 +9434,13 @@ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), FALSE); gtk_notebook_set_show_border(GTK_NOTEBOOK(win->notebook), TRUE); - /* TODO: figure out how to add custom stuff to the right-click menu in - GtkNotebook in GTK+ 3.0 */ - /* + /* TODO: figure out how to add custom stuff to the right-click menu in + GtkNotebook in GTK+ 3.0 */ +#if 0 g_signal_connect(G_OBJECT(win->notebook), "button-press-event", G_CALLBACK(right_click_menu_cb), win); - */ - +#endif + gtk_widget_show(win->notebook); g_signal_connect(G_OBJECT(win->notebook), "switch_page", diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkconv.h --- a/pidgin/gtkconv.h Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkconv.h Mon Apr 25 20:13:05 2011 +0000 @@ -182,7 +182,11 @@ GList *current; } attach; - /* Quick Find (since 2.7.0) */ + /** + * Quick Find. + * + * @since 2.7.0 + */ struct { GtkWidget *entry; GtkWidget *container; diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkdialogs.c Mon Apr 25 20:13:05 2011 +0000 @@ -454,7 +454,7 @@ button = pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CLOSE, G_CALLBACK(destroy_win), win); - gtk_widget_set_can_default(button, TRUE); + gtk_widget_set_can_default(button, TRUE); gtk_widget_grab_default(button); gtk_widget_show_all(win); @@ -650,14 +650,6 @@ else g_string_append(str, " Perl: Disabled
"); -#ifndef _WIN32 -#ifdef HAVE_STARTUP_NOTIFICATION - g_string_append(str, " Startup Notification: Enabled
"); -#else - g_string_append(str, " Startup Notification: Disabled
"); -#endif -#endif - if (purple_plugins_find_with_id("core-tcl") != NULL) { g_string_append(str, " Tcl: Enabled
"); #ifdef HAVE_TK @@ -901,12 +893,12 @@ gtk_container_set_border_width (GTK_CONTAINER(window), PIDGIN_HIG_BOX_SPACE); gtk_window_set_resizable(GTK_WINDOW(window), FALSE); - /* TODO: figure out how to set no separator in a dialog in GTK+ 3.0 */ - /*gtk_dialog_set_has_separator(GTK_DIALOG(window), FALSE);*/ + /* TODO: figure out how to set no separator in a dialog in GTK+ 3.0 */ + /*gtk_dialog_set_has_separator(GTK_DIALOG(window), FALSE);*/ gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))), - PIDGIN_HIG_BORDER); - gtk_container_set_border_width (GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(window))), - PIDGIN_HIG_BOX_SPACE); + PIDGIN_HIG_BORDER); + gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(window))), + PIDGIN_HIG_BOX_SPACE); hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(window))), hbox); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkdocklet-gtk.c --- a/pidgin/gtkdocklet-gtk.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkdocklet-gtk.c Mon Apr 25 20:13:05 2011 +0000 @@ -47,19 +47,37 @@ static gboolean docklet_gtk_embed_timeout_cb(gpointer data) { - /* The docklet was not embedded within the timeout. - * Remove it as a visibility manager, but leave the plugin - * loaded so that it can embed automatically if/when a notification - * area becomes available. - */ - purple_debug_info("docklet", "failed to embed within timeout\n"); - pidgin_docklet_remove(); - purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE); +#if !GTK_CHECK_VERSION(2,12,0) + if (gtk_status_icon_is_embedded(docklet)) { + /* Older GTK+ (<2.12) don't implement the embedded signal, but the + information is still accessable through the above function. */ + purple_debug_info("docklet", "embedded\n"); + pidgin_docklet_embedded(); + purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE); + } + else +#endif + { + /* The docklet was not embedded within the timeout. + * Remove it as a visibility manager, but leave the plugin + * loaded so that it can embed automatically if/when a notification + * area becomes available. + */ + purple_debug_info("docklet", "failed to embed within timeout\n"); + pidgin_docklet_remove(); + purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE); + } + +#if GTK_CHECK_VERSION(2,12,0) embed_timeout = 0; return FALSE; +#else + return TRUE; +#endif } +#if GTK_CHECK_VERSION(2,12,0) static gboolean docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data) { @@ -82,6 +100,7 @@ return TRUE; } +#endif static void docklet_gtk_destroyed_cb(GtkWidget *widget, gpointer data) @@ -200,7 +219,9 @@ g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL); g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL); +#if GTK_CHECK_VERSION(2,12,0) g_signal_connect(G_OBJECT(docklet), "notify::embedded", G_CALLBACK(docklet_gtk_embedded_cb), NULL); +#endif g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_gtk_destroyed_cb), NULL); gtk_status_icon_set_visible(docklet, TRUE); @@ -220,11 +241,15 @@ */ if (!recreate) { pidgin_docklet_embedded(); +#if GTK_CHECK_VERSION(2,12,0) if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) { embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL); } else { embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL); } +#else + embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL); +#endif } purple_debug_info("docklet", "GTK+ created\n"); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkft.c --- a/pidgin/gtkft.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkft.c Mon Apr 25 20:13:05 2011 +0000 @@ -557,22 +557,12 @@ static GtkWidget * setup_tree(PidginXferDialog *dialog) { - GtkWidget *sw; GtkWidget *tree; GtkListStore *model; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; - /* Create the scrolled window. */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_widget_show(sw); - /* Build the tree model */ /* Transfer type, Progress Bar, Filename, Size, Remaining */ model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_INT, @@ -636,10 +626,9 @@ gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree)); - gtk_container_add(GTK_CONTAINER(sw), tree); gtk_widget_show(tree); - return sw; + return tree; } static GtkWidget * @@ -713,7 +702,6 @@ PidginXferDialog *dialog; GtkWidget *window; GtkWidget *vbox1, *vbox2; - GtkWidget *sw; GtkWidget *expander; GtkWidget *alignment; GtkWidget *table; @@ -744,9 +732,9 @@ gtk_widget_show(vbox2); /* Setup the listbox */ - sw = setup_tree(dialog); - gtk_box_pack_start(GTK_BOX(vbox2), sw, TRUE, TRUE, 0); - gtk_widget_set_size_request(sw,-1, 140); + gtk_box_pack_start(GTK_BOX(vbox2), + pidgin_make_scrollable(setup_tree(dialog), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 140), + TRUE, TRUE, 0); /* "Close this window when all transfers finish" */ checkbox = gtk_check_button_new_with_mnemonic( diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkimhtml.c --- a/pidgin/gtkimhtml.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkimhtml.c Mon Apr 25 20:13:05 2011 +0000 @@ -1073,7 +1073,7 @@ } if (primary) /* This was allocated here */ g_free(text); - } +} static void gtk_imhtml_primary_clipboard_clear(GtkClipboard *clipboard, GtkIMHtml *imhtml) { @@ -1342,7 +1342,7 @@ paste_received_cb, imhtml); return TRUE; - } + } return FALSE; } @@ -1904,10 +1904,10 @@ gdk_drag_status (context, suggested_action, time); - /* TRUE return means don't propagate the drag motion to parent - * widgets that may also be drop sites. - */ - return TRUE; + /* TRUE return means don't propagate the drag motion to parent + * widgets that may also be drop sites. + */ + return TRUE; } static void @@ -1966,7 +1966,7 @@ i++; } - g_strfreev(links); + g_strfreev(links); break; case GTK_IMHTML_DRAG_HTML: { @@ -4260,7 +4260,7 @@ gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, &iter, e); g_free(name); - } + } g_slist_free(tags); } @@ -5010,7 +5010,7 @@ } } } else { - imhtml->num_animations++; + imhtml->num_animations++; } g_signal_connect(G_OBJECT(icon), "destroy", G_CALLBACK(animated_smiley_destroy_cb), imhtml); g_queue_push_tail(imhtml->animations, icon); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkimhtmltoolbar.c --- a/pidgin/gtkimhtmltoolbar.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Mon Apr 25 20:13:05 2011 +0000 @@ -125,14 +125,14 @@ GtkFontSelection *sel; sel = GTK_FONT_SELECTION( - gtk_font_selection_dialog_get_font_selection(GTK_FONT_SELECTION_DIALOG(toolbar->font_dialog))); + gtk_font_selection_dialog_get_font_selection(GTK_FONT_SELECTION_DIALOG(toolbar->font_dialog))); gtk_widget_hide(gtk_widget_get_parent( - gtk_font_selection_get_size_entry(sel))); + gtk_font_selection_get_size_entry(sel))); gtk_widget_show_all(gtk_font_selection_get_family_list(sel)); gtk_widget_show(gtk_widget_get_parent( - gtk_font_selection_get_family_list(sel))); + gtk_font_selection_get_family_list(sel))); gtk_widget_show(gtk_widget_get_parent(gtk_widget_get_parent( - gtk_font_selection_get_family_list(sel)))); + gtk_font_selection_get_family_list(sel)))); } static void @@ -196,11 +196,11 @@ g_signal_connect(G_OBJECT(toolbar->font_dialog), "delete_event", G_CALLBACK(destroy_toolbar_font), toolbar); g_signal_connect(G_OBJECT( - gtk_font_selection_dialog_get_ok_button(GTK_FONT_SELECTION_DIALOG(toolbar->font_dialog))), - "clicked", G_CALLBACK(apply_font), toolbar->font_dialog); + gtk_font_selection_dialog_get_ok_button(GTK_FONT_SELECTION_DIALOG(toolbar->font_dialog))), + "clicked", G_CALLBACK(apply_font), toolbar->font_dialog); g_signal_connect(G_OBJECT( - gtk_font_selection_dialog_get_cancel_button(GTK_FONT_SELECTION_DIALOG(toolbar->font_dialog))), - "clicked", G_CALLBACK(cancel_toolbar_font), toolbar); + gtk_font_selection_dialog_get_cancel_button(GTK_FONT_SELECTION_DIALOG(toolbar->font_dialog))), + "clicked", G_CALLBACK(cancel_toolbar_font), toolbar); g_signal_connect_after(G_OBJECT(toolbar->font_dialog), "realize", G_CALLBACK(realize_toolbar_font), toolbar); } @@ -259,12 +259,12 @@ char *color = gtk_imhtml_get_current_forecolor(GTK_IMHTML(toolbar->imhtml)); if (!toolbar->fgcolor_dialog) { - GtkWidget *ok_button; - GtkWidget *cancel_button; - + GtkWidget *ok_button; + GtkWidget *cancel_button; + toolbar->fgcolor_dialog = gtk_color_selection_dialog_new(_("Select Text Color")); colorsel = - gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(toolbar->fgcolor_dialog)); + gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(toolbar->fgcolor_dialog)); if (color) { gdk_color_parse(color, &fgcolor); gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(colorsel), &fgcolor); @@ -273,14 +273,13 @@ g_object_set_data(G_OBJECT(colorsel), "purple_toolbar", toolbar); - g_object_get(G_OBJECT(toolbar->fgcolor_dialog), "ok-button", &ok_button, NULL); - g_object_get(G_OBJECT(toolbar->fgcolor_dialog), "cancel-button", - &cancel_button, NULL); + g_object_get(G_OBJECT(toolbar->fgcolor_dialog), "ok-button", &ok_button, NULL); + g_object_get(G_OBJECT(toolbar->fgcolor_dialog), "cancel-button", &cancel_button, NULL); g_signal_connect(G_OBJECT(toolbar->fgcolor_dialog), "delete_event", G_CALLBACK(destroy_toolbar_fgcolor), toolbar); g_signal_connect(G_OBJECT(ok_button), "clicked", G_CALLBACK(do_fgcolor), colorsel); g_signal_connect(G_OBJECT(cancel_button), "clicked", - G_CALLBACK(cancel_toolbar_fgcolor), toolbar); + G_CALLBACK(cancel_toolbar_fgcolor), toolbar); } gtk_window_present(GTK_WINDOW(toolbar->fgcolor_dialog)); } else { @@ -344,14 +343,14 @@ char *color = gtk_imhtml_get_current_backcolor(GTK_IMHTML(toolbar->imhtml)); if (!toolbar->bgcolor_dialog) { - GtkWidget *ok_button; - GtkWidget *cancel_button; - + GtkWidget *ok_button; + GtkWidget *cancel_button; + toolbar->bgcolor_dialog = gtk_color_selection_dialog_new(_("Select Background Color")); colorsel = - gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(toolbar->fgcolor_dialog)); + gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(toolbar->fgcolor_dialog)); - if (color) { + if (color) { gdk_color_parse(color, &bgcolor); gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(colorsel), &bgcolor); g_free(color); @@ -359,13 +358,13 @@ g_object_set_data(G_OBJECT(colorsel), "purple_toolbar", toolbar); - g_object_get(G_OBJECT(toolbar->bgcolor_dialog), "ok-button", &ok_button, NULL); - g_object_get(G_OBJECT(toolbar->bgcolor_dialog), "cancel-button", - &cancel_button, NULL); + g_object_get(G_OBJECT(toolbar->bgcolor_dialog), "ok-button", &ok_button, NULL); + g_object_get(G_OBJECT(toolbar->bgcolor_dialog), "cancel-button", + &cancel_button, NULL); g_signal_connect(G_OBJECT(toolbar->bgcolor_dialog), "delete_event", G_CALLBACK(destroy_toolbar_bgcolor), toolbar); g_signal_connect(G_OBJECT(ok_button), "clicked", - G_CALLBACK(do_bgcolor), colorsel); + G_CALLBACK(do_bgcolor), colorsel); g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(cancel_toolbar_bgcolor), toolbar); @@ -479,12 +478,12 @@ static void insert_hr_cb(GtkWidget *widget, GtkIMHtmlToolbar *toolbar) { - GtkTextIter iter; - GtkTextMark *ins; + GtkTextIter iter; + GtkTextMark *ins; GtkIMHtmlScalable *hr; - ins = gtk_text_buffer_get_insert(gtk_text_view_get_buffer(GTK_TEXT_VIEW(toolbar->imhtml))); - gtk_text_buffer_get_iter_at_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(toolbar->imhtml)), &iter, ins); + ins = gtk_text_buffer_get_insert(gtk_text_view_get_buffer(GTK_TEXT_VIEW(toolbar->imhtml))); + gtk_text_buffer_get_iter_at_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(toolbar->imhtml)), &iter, ins); hr = gtk_imhtml_hr_new(); gtk_imhtml_hr_add_to(hr, GTK_IMHTML(toolbar->imhtml), &iter); } @@ -884,14 +883,9 @@ g_signal_connect(G_OBJECT(dialog), "button-press-event", (GCallback)smiley_dialog_input_cb, toolbar); } - scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_NONE); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_NEVER, GTK_POLICY_NEVER); + + scrolled = pidgin_make_scrollable(smiley_table, GTK_POLICY_NEVER, GTK_POLICY_NEVER, GTK_SHADOW_NONE, -1, -1); gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0); - gtk_widget_show(scrolled); - - gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), smiley_table); gtk_widget_show(smiley_table); viewport = gtk_widget_get_parent(smiley_table); @@ -916,8 +910,10 @@ * makes one or both scrollbars visible (sometimes). * I too think this hack is gross. But I couldn't find a better way -- sadrul */ gtk_window_set_resizable(GTK_WINDOW(dialog), TRUE); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + g_object_set(G_OBJECT(scrolled), + "hscrollbar-policy", GTK_POLICY_AUTOMATIC, + "vscrollbar-policy", GTK_POLICY_AUTOMATIC, + NULL); #ifdef _WIN32 winpidgin_ensure_onscreen(dialog); @@ -1113,11 +1109,11 @@ { GtkWidget *widget = GTK_WIDGET(data); GtkRequisition menu_req; - GtkAllocation allocation; - gint ythickness = gtk_widget_get_style(widget)->ythickness; + GtkAllocation allocation; + gint ythickness = gtk_widget_get_style(widget)->ythickness; int savy; - gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_allocation(widget, &allocation); gtk_widget_size_request(GTK_WIDGET (menu), &menu_req); gdk_window_get_origin(gtk_widget_get_window(widget), x, y); *x += allocation.x; diff -r a92f4cb593a4 -r 974722699032 pidgin/gtklog.c --- a/pidgin/gtklog.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtklog.c Mon Apr 25 20:13:05 2011 +0000 @@ -531,7 +531,6 @@ GtkWidget *title_box; char *text; GtkWidget *pane; - GtkWidget *sw; GtkCellRenderer *rend; GtkTreeViewColumn *col; GtkTreeSelection *sel; @@ -582,10 +581,11 @@ gtk_dialog_add_button(GTK_DIALOG(lv->window), _("_Browse logs folder"), GTK_RESPONSE_HELP); #endif gtk_container_set_border_width (GTK_CONTAINER(lv->window), PIDGIN_HIG_BOX_SPACE); - /* TODO: is it possible to set this in GTK+ 3.0? - gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE); - */ - gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv->window))), 0); + /* TODO: is it possible to set this in GTK+ 3.0? */ +#if 0 + gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE); +#endif + gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv->window))), 0); g_signal_connect(G_OBJECT(lv->window), "response", G_CALLBACK(destroy_cb), ht); gtk_window_set_role(GTK_WINDOW(lv->window), "log_viewer"); @@ -595,7 +595,7 @@ title_box = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); gtk_container_set_border_width(GTK_CONTAINER(title_box), PIDGIN_HIG_BOX_SPACE); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv->window))), - title_box, FALSE, FALSE, 0); + title_box, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(title_box), icon, FALSE, FALSE, 0); } else @@ -615,13 +615,9 @@ pane = gtk_hpaned_new(); gtk_container_set_border_width(GTK_CONTAINER(pane), PIDGIN_HIG_BOX_SPACE); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv->window))), - pane, TRUE, TRUE, 0); + pane, TRUE, TRUE, 0); /* List *************/ - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - gtk_paned_add1(GTK_PANED(pane), sw); lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore)); g_object_unref(G_OBJECT(lv->treestore)); @@ -629,7 +625,8 @@ col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE); - gtk_container_add (GTK_CONTAINER (sw), lv->treeview); + gtk_paned_add1(GTK_PANED(pane), + pidgin_make_scrollable(lv->treeview, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1)); populate_log_tree(lv); @@ -654,7 +651,7 @@ /* gtk_paned_add1(GTK_PANED(pane), size_label); */ gtk_misc_set_alignment(GTK_MISC(size_label), 0, 0); gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv->window))), - size_label, FALSE, FALSE, 0); + size_label, FALSE, FALSE, 0); g_free(sz_txt); g_free(text); } diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkmain.c --- a/pidgin/gtkmain.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkmain.c Mon Apr 25 20:13:05 2011 +0000 @@ -76,18 +76,6 @@ #include -#ifdef HAVE_STARTUP_NOTIFICATION -# define SN_API_NOT_YET_FROZEN -# include -# include -#endif - - - -#ifdef HAVE_STARTUP_NOTIFICATION -static SnLauncheeContext *sn_context = NULL; -static SnDisplay *sn_display = NULL; -#endif #ifdef HAVE_SIGNAL_H @@ -472,42 +460,6 @@ g_free(text); } -#ifdef HAVE_STARTUP_NOTIFICATION -static void -sn_error_trap_push(SnDisplay *display, Display *xdisplay) -{ - gdk_error_trap_push(); -} - -static void -sn_error_trap_pop(SnDisplay *display, Display *xdisplay) -{ - gdk_error_trap_pop(); -} - -static void -startup_notification_complete(void) -{ - Display *xdisplay; - - xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); - sn_display = sn_display_new(xdisplay, - sn_error_trap_push, - sn_error_trap_pop); - sn_context = - sn_launchee_context_new_from_environment(sn_display, - DefaultScreen(xdisplay)); - - if (sn_context != NULL) - { - sn_launchee_context_complete(sn_context); - sn_launchee_context_unref(sn_context); - - sn_display_unref(sn_display); - } -} -#endif /* HAVE_STARTUP_NOTIFICATION */ - /* FUCKING GET ME A TOWEL! */ #ifdef _WIN32 /* suppress gcc "no previous prototype" warning */ @@ -876,6 +828,7 @@ dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); #endif + gdk_notify_startup_complete(); purple_core_quit(); g_printerr(_("Exiting because another libpurple client is already running.\n")); #ifdef HAVE_SIGNAL_H @@ -967,9 +920,10 @@ g_list_free(active_accounts); } -#ifdef HAVE_STARTUP_NOTIFICATION - startup_notification_complete(); -#endif + /* GTK clears the notification for us when opening the first window, + * but we may have launched with only a status icon, so clear the it + * just in case. */ + gdk_notify_startup_complete(); #ifdef _WIN32 winpidgin_post_init(); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkmedia.c --- a/pidgin/gtkmedia.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkmedia.c Mon Apr 25 20:13:05 2011 +0000 @@ -363,7 +363,7 @@ progress = gtkmedia->priv->send_progress; else progress = gtkmedia->priv->recv_progress; - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), level); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), level * 5); } diff -r a92f4cb593a4 -r 974722699032 pidgin/gtknotify.c --- a/pidgin/gtknotify.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtknotify.c Mon Apr 25 20:13:05 2011 +0000 @@ -534,18 +534,19 @@ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - /* TODO: not sure if there is a way to do this in gtk+ 3, or - if we want to... + /* TODO: not sure if there is a way to do this in gtk+ 3, or + if we want to... */ +#if 0 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - */ - gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER); +#endif + gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), + PIDGIN_HIG_BORDER); gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BOX_SPACE); + PIDGIN_HIG_BOX_SPACE); hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - hbox); + hbox); if (img != NULL) gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); @@ -962,7 +963,6 @@ GtkWidget *vbox; GtkWidget *label; - GtkWidget *sw; PidginNotifySearchResultsData *data; char *label_text; char *primary_esc, *secondary_esc; @@ -1018,15 +1018,6 @@ model = gtk_list_store_newv(col_num, col_types); g_free(col_types); - /* Setup the scrolled window containing the treeview */ - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - gtk_widget_show(sw); - /* Setup the treeview */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); g_object_unref(G_OBJECT(model)); @@ -1035,7 +1026,9 @@ gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_SINGLE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), treeview); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 0); gtk_widget_show(treeview); renderer = gtk_cell_renderer_pixbuf_new(); @@ -1494,7 +1487,6 @@ GtkTreeStore *model = NULL; GtkWidget *dialog = NULL; GtkWidget *label = NULL; - GtkWidget *sw; GtkCellRenderer *rend; GtkTreeViewColumn *column; GtkWidget *button = NULL; @@ -1523,12 +1515,13 @@ /* Setup the dialog */ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE); gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BOX_SPACE); - /* TODO: not sure if this is possible (or nessesary) in gtk+ 3 + PIDGIN_HIG_BOX_SPACE); + /* TODO: not sure if this is possible (or necessary) in gtk+ 3 */ +#if 0 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - */ +#endif gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER); + PIDGIN_HIG_BORDER); /* Vertical box */ vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); @@ -1536,10 +1529,6 @@ /* Golden ratio it up! */ gtk_widget_set_size_request(dialog, 550, 400); - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - spec_dialog = g_new0(PidginNotifyDialog, 1); spec_dialog->dialog = dialog; @@ -1548,7 +1537,6 @@ g_object_unref(G_OBJECT(model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spec_dialog->treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), spec_dialog->treeview); if (type == PIDGIN_NOTIFY_MAIL) { gtk_window_set_title(GTK_WINDOW(dialog), _("New Mail")); @@ -1602,8 +1590,15 @@ gtk_widget_set_sensitive(button, FALSE); spec_dialog->edit_button = button; - button = gtk_dialog_add_button(GTK_DIALOG(dialog), - _("Dismiss"), GTK_RESPONSE_NO); + /* Translators: Make sure you translate "Dismiss" differently than + "close"! This string is used in the "You have pounced" dialog + that appears when one of your Buddy Pounces is triggered. In + this context "Dismiss" means "I acknowledge that I've seen that + this pounce was triggered--remove it from this list." Translating + it as "Remove" is acceptable if you can't think of a more precise + word. */ + button = gtk_dialog_add_button(GTK_DIALOG(dialog), _("Dismiss"), + GTK_RESPONSE_NO); gtk_widget_set_sensitive(button, FALSE); spec_dialog->dismiss_button = button; @@ -1663,7 +1658,9 @@ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(spec_dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 2); return spec_dialog; } diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkplugin.c --- a/pidgin/gtkplugin.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkplugin.c Mon Apr 25 20:13:05 2011 +0000 @@ -562,13 +562,13 @@ pidgin_plugins_paint_tooltip(GtkWidget *tipwindow, gpointer data) { PangoLayout *layout = g_object_get_data(G_OBJECT(tipwindow), "tooltip-plugin"); - cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(tipwindow)); - gtk_paint_layout(gtk_widget_get_style(tipwindow), cr, GTK_STATE_NORMAL, FALSE, + cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(tipwindow)); + gtk_paint_layout(gtk_widget_get_style(tipwindow), cr, GTK_STATE_NORMAL, FALSE, tipwindow, "tooltip", 6, 6, layout); - cairo_destroy(cr); + cairo_destroy(cr); - return TRUE; + return TRUE; } static gboolean @@ -709,7 +709,6 @@ void pidgin_plugin_dialog_show() { - GtkWidget *sw; GtkWidget *event_view; GtkListStore *ls; GtkCellRenderer *rend, *rendt; @@ -733,13 +732,6 @@ gtk_widget_set_sensitive(pref_button, FALSE); gtk_window_set_role(GTK_WINDOW(plugin_dialog), "plugins"); - sw = gtk_scrolled_window_new(NULL,NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - - gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(plugin_dialog))), - sw, TRUE, TRUE, 0); - ls = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), 1, GTK_SORT_ASCENDING); @@ -784,7 +776,9 @@ gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col); gtk_tree_view_column_set_sort_column_id(col, 1); g_object_unref(G_OBJECT(ls)); - gtk_container_add(GTK_CONTAINER(sw), event_view); + gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(plugin_dialog))), + pidgin_make_scrollable(event_view, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 0); gtk_tree_view_set_search_column(GTK_TREE_VIEW(event_view), 1); gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(event_view), pidgin_tree_view_search_equal_func, NULL, NULL); @@ -799,7 +793,7 @@ gtk_widget_set_sensitive(expander, FALSE); gtk_container_add(GTK_CONTAINER(expander), create_details()); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(plugin_dialog))), - expander, FALSE, FALSE, 0); + expander, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (prefs_plugin_sel), NULL); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkpounce.c --- a/pidgin/gtkpounce.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkpounce.c Mon Apr 25 20:13:05 2011 +0000 @@ -410,9 +410,9 @@ GtkSelectionData *sd, guint info, guint t, gpointer data) { PidginPounceDialog *dialog; - GdkAtom target = gtk_selection_data_get_target(sd); - const guchar *sd_data = gtk_selection_data_get_data(sd); - + GdkAtom target = gtk_selection_data_get_target(sd); + const guchar *sd_data = gtk_selection_data_get_data(sd); + if (target == gdk_atom_intern("PURPLE_BLIST_NODE", FALSE)) { PurpleBlistNode *node = NULL; @@ -1223,21 +1223,11 @@ static GtkWidget * create_pounces_list(PouncesManager *dialog) { - GtkWidget *sw; GtkWidget *treeview; GtkTreeSelection *sel; GtkTreeViewColumn *column; GtkCellRenderer *renderer; - /* Create the scrolled window */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_widget_show(sw); - /* Create the list model */ dialog->model = gtk_list_store_new(POUNCES_MANAGER_NUM_COLUMNS, G_TYPE_POINTER, @@ -1261,7 +1251,6 @@ /* Handle double-clicking */ g_signal_connect(G_OBJECT(treeview), "button_press_event", G_CALLBACK(pounce_double_click_cb), dialog); - gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); /* Pouncee Column */ @@ -1321,7 +1310,7 @@ /* Populate list */ populate_pounces_list(dialog); - return sw; + return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1); } void diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkprefs.c --- a/pidgin/gtkprefs.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkprefs.c Mon Apr 25 20:13:05 2011 +0000 @@ -867,7 +867,7 @@ gchar *name = g_strchomp((gchar *)gtk_selection_data_get_data(sd)); if ((gtk_selection_data_get_length(sd) >= 0) - && (gtk_selection_data_get_format(sd) == 8)) { + && (gtk_selection_data_get_format(sd) == 8)) { /* Well, it looks like the drag event was cool. * Let's do something with it */ gchar *temp; @@ -2540,27 +2540,20 @@ sound_changed2_cb, vbox); #endif vbox = pidgin_make_frame(ret, _("Sound Events")); - parent = gtk_widget_get_parent(vbox); - parent_parent = gtk_widget_get_parent(parent); - parent_parent_parent = gtk_widget_get_parent(parent_parent); - + parent = gtk_widget_get_parent(vbox); + parent_parent = gtk_widget_get_parent(parent); + parent_parent_parent = gtk_widget_get_parent(parent_parent); + /* The following is an ugly hack to make the frame expand so the * sound events list is big enough to be usable */ gtk_box_set_child_packing(GTK_BOX(parent), vbox, TRUE, TRUE, 0, GTK_PACK_START); gtk_box_set_child_packing(GTK_BOX(parent_parent), - parent, TRUE, TRUE, 0, GTK_PACK_START); - gtk_box_set_child_packing( - GTK_BOX(parent_parent_parent), + parent, TRUE, TRUE, 0, GTK_PACK_START); + gtk_box_set_child_packing(GTK_BOX(parent_parent_parent), parent_parent, TRUE, TRUE, 0, GTK_PACK_START); /* SOUND SELECTION */ - sw = gtk_scrolled_window_new(NULL,NULL); - gtk_widget_set_size_request(sw, -1, 100); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); event_store = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); for (j=0; j < PURPLE_NUM_SOUNDS; j++) { @@ -2609,7 +2602,9 @@ NULL); gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col); g_object_unref(G_OBJECT(event_store)); - gtk_container_add(GTK_CONTAINER(sw), event_view); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(event_view, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 100), + TRUE, TRUE, 0); hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkprivacy.c --- a/pidgin/gtkprivacy.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkprivacy.c Mon Apr 25 20:13:05 2011 +0000 @@ -133,12 +133,6 @@ GtkTreeViewColumn *column; GtkTreeSelection *sel; - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); *ret_treeview = treeview; @@ -150,7 +144,7 @@ gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); - gtk_container_add(GTK_CONTAINER(sw), treeview); + sw = pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 200); gtk_widget_show(treeview); @@ -159,8 +153,6 @@ g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(user_selected_cb), dialog); - gtk_widget_set_size_request(sw, -1, 200); - return sw; } diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkrequest.c --- a/pidgin/gtkrequest.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkrequest.c Mon Apr 25 20:13:05 2011 +0000 @@ -106,9 +106,9 @@ if (GTK_IS_DIALOG(cont)) { gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(cont))), - image, FALSE, TRUE, 0); + image, FALSE, TRUE, 0); gtk_box_reorder_child(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(cont))), - image, 0); + image, 0); } else if (GTK_IS_HBOX(cont)) { gtk_misc_set_alignment(GTK_MISC(image), 0, 0); gtk_box_pack_end(GTK_BOX(cont), image, FALSE, TRUE, 0); @@ -362,20 +362,21 @@ /* Setup the dialog */ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2); gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER / 2); + PIDGIN_HIG_BORDER / 2); if (!multiline) gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - /* TODO: not sure how to do this with GTK+ 3 + /* TODO: not sure how to do this with GTK+ 3 */ +#if 0 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - */ +#endif gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0); gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER); + PIDGIN_HIG_BORDER); /* Setup the main horizontal box */ hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - hbox); + hbox); /* Dialog icon. */ img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION, @@ -432,16 +433,6 @@ } else { if (multiline) { - GtkWidget *sw; - - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - - gtk_widget_set_size_request(sw, 320, 130); - /* GtkTextView */ entry = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(entry), TRUE); @@ -455,12 +446,12 @@ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(entry), GTK_WRAP_WORD_CHAR); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/spellcheck")) pidgin_setup_gtkspell(GTK_TEXT_VIEW(entry)); - gtk_container_add(GTK_CONTAINER(sw), entry); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(entry, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, 320, 130), + TRUE, TRUE, 0); } else { entry = gtk_entry_new(); @@ -544,18 +535,19 @@ /* Setup the dialog */ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2); gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER / 2); + PIDGIN_HIG_BORDER / 2); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - /* TODO: don't know if this is possible with GTK+ 3 - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - */ + /* TODO: don't know if this is possible with GTK+ 3 */ +#if 0 + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); +#endif gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER); + PIDGIN_HIG_BORDER); /* Setup the main horizontal box */ hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - hbox); + hbox); /* Dialog icon. */ img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION, @@ -671,18 +663,19 @@ /* Setup the dialog */ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2); gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER / 2); + PIDGIN_HIG_BORDER / 2); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); - /* TODO: this is probably not supported by GTK+ 3 - gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); - */ + /* TODO: this is probably not supported by GTK+ 3 */ +#if 0 + gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); +#endif gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - PIDGIN_HIG_BORDER); + PIDGIN_HIG_BORDER); /* Setup the main horizontal box */ hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - hbox); + hbox); /* Dialog icon. */ if (icon_data) { @@ -753,8 +746,8 @@ if (default_action == PURPLE_DEFAULT_ACTION_NONE) { - gtk_widget_set_can_default(img, TRUE); - gtk_widget_set_can_focus(img, TRUE); + gtk_widget_set_can_default(img, TRUE); + gtk_widget_set_can_focus(img, TRUE); gtk_widget_grab_focus(img); gtk_widget_grab_default(img); } else @@ -875,12 +868,6 @@ { GtkWidget *textview; - widget = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), - GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - textview = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), TRUE); @@ -890,11 +877,8 @@ if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/spellcheck")) pidgin_setup_gtkspell(GTK_TEXT_VIEW(textview)); - gtk_container_add(GTK_CONTAINER(widget), textview); gtk_widget_show(textview); - gtk_widget_set_size_request(widget, -1, 75); - if (value != NULL) { GtkTextBuffer *buffer; @@ -916,6 +900,8 @@ g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(req_entry_field_changed_cb), field); } + + widget = pidgin_make_scrollable(textview, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, 75); } else { @@ -1116,7 +1102,6 @@ static GtkWidget * create_list_field(PurpleRequestField *field) { - GtkWidget *sw; GtkWidget *treeview; GtkListStore *store; GtkCellRenderer *renderer; @@ -1128,14 +1113,6 @@ icons = purple_request_field_list_get_icons(field); - /* Create the scrolled window */ - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_widget_show(sw); /* Create the list store */ if (icons) @@ -1211,10 +1188,9 @@ g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(list_field_select_changed_cb), field); - gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(treeview); - return sw; + return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1); } static void * @@ -1235,7 +1211,6 @@ GtkWidget *table; GtkWidget *button; GtkWidget *img; - GtkWidget *sw; GtkSizeGroup *sg; GList *gl, *fl; PurpleRequestFieldGroup *group; @@ -1281,12 +1256,12 @@ /* Cancel button */ button = pidgin_dialog_add_button(GTK_DIALOG(win), text_to_stock(cancel_text), G_CALLBACK(multifield_cancel_cb), data); - gtk_widget_set_can_default(button, TRUE); + gtk_widget_set_can_default(button, TRUE); /* OK button */ button = pidgin_dialog_add_button(GTK_DIALOG(win), text_to_stock(ok_text), G_CALLBACK(multifield_ok_cb), data); data->ok_button = button; - gtk_widget_set_can_default(button, TRUE); + gtk_widget_set_can_default(button, TRUE); gtk_window_set_default(GTK_WINDOW(win), button); pidgin_widget_decorate_account(hbox, account); @@ -1320,18 +1295,10 @@ if(total_fields > 9) { GtkWidget *hbox_for_spacing, *vbox_for_spacing; - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_NONE); - gtk_widget_set_size_request(sw, -1, 200); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - gtk_widget_show(sw); - hbox_for_spacing = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); - gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), - hbox_for_spacing); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(hbox_for_spacing, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, 200), + TRUE, TRUE, 0); gtk_widget_show(hbox_for_spacing); vbox_for_spacing = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkroomlist.c --- a/pidgin/gtkroomlist.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkroomlist.c Mon Apr 25 20:13:05 2011 +0000 @@ -359,9 +359,8 @@ int current_height, max_width; int max_text_width; GtkTextDirection dir = gtk_widget_get_direction(GTK_WIDGET(grl->tree)); - cairo_t *cr = - gdk_cairo_create(gtk_widget_get_window(grl->tipwindow)); - + cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(grl->tipwindow)); + style = gtk_widget_get_style(grl->tipwindow); max_text_width = MAX(grl->tip_width, grl->tip_name_width); @@ -390,7 +389,7 @@ current_height + grl->tip_name_height, grl->tip_layout); } - cairo_destroy(cr); + cairo_destroy(cr); return FALSE; } @@ -552,15 +551,8 @@ pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("_Account:"), NULL, dialog->account_widget, TRUE, NULL); /* scrolled window */ - dialog->sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); + dialog->sw = pidgin_make_scrollable(NULL, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, 250); gtk_box_pack_start(GTK_BOX(vbox2), dialog->sw, TRUE, TRUE, 0); - gtk_widget_set_size_request(dialog->sw, -1, 250); - gtk_widget_show(dialog->sw); /* progress bar */ dialog->progress = gtk_progress_bar_new(); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtksavedstatuses.c --- a/pidgin/gtksavedstatuses.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtksavedstatuses.c Mon Apr 25 20:13:05 2011 +0000 @@ -438,20 +438,11 @@ static GtkWidget * create_saved_status_list(StatusWindow *dialog) { - GtkWidget *sw; GtkWidget *treeview; GtkTreeSelection *sel; GtkTreeViewColumn *column; GtkCellRenderer *renderer; - /* Create the scrolled window */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - /* Create the list model */ dialog->model = gtk_list_store_new(STATUS_WINDOW_NUM_COLUMNS, G_TYPE_STRING, @@ -472,8 +463,6 @@ g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(status_selected_cb), dialog); - gtk_container_add(GTK_CONTAINER(sw), treeview); - /* Add columns */ column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Title")); @@ -527,9 +516,9 @@ /* Populate list */ populate_saved_status_list(dialog); - gtk_widget_show_all(sw); + gtk_widget_show_all(treeview); - return sw; + return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1); } static gboolean @@ -1092,7 +1081,6 @@ GtkWidget *entry; GtkWidget *frame; GtkWidget *hbox; - GtkWidget *sw; GtkWidget *text; GtkWidget *toolbar; GtkWidget *vbox; @@ -1181,14 +1169,6 @@ dbox = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); gtk_container_add(GTK_CONTAINER(expander), dbox); - /* Different status message treeview */ - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(dbox), sw, TRUE, TRUE, 0); - /* Create the list model */ dialog->model = gtk_list_store_new(STATUS_EDITOR_NUM_COLUMNS, G_TYPE_POINTER, @@ -1205,7 +1185,9 @@ dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); gtk_widget_set_size_request(dialog->treeview, -1, 150); - gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); + gtk_box_pack_start(GTK_BOX(dbox), + pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 0); /* Add columns */ status_editor_add_columns(dialog); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtksession.c --- a/pidgin/gtksession.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtksession.c Mon Apr 25 20:13:05 2011 +0000 @@ -349,7 +349,7 @@ free(tmp); session_managed = TRUE; - gdk_set_sm_client_id(client_id); + gdk_x11_set_sm_client_id(client_id); tmp = g_get_current_dir(); session_set_string(session, SmCurrentDirectory, tmp); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtksmiley.c --- a/pidgin/gtksmiley.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtksmiley.c Mon Apr 25 20:13:05 2011 +0000 @@ -776,7 +776,6 @@ static GtkWidget *smiley_list_create(SmileyManager *dialog) { - GtkWidget *sw; GtkWidget *treeview; GtkTreeSelection *sel; GtkTargetEntry te[3] = { @@ -785,14 +784,6 @@ {"STRING", 0, 2} }; - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_widget_show(sw); - /* Create the list model */ dialog->model = gtk_list_store_new(N_COL, GDK_TYPE_PIXBUF, /* ICON */ @@ -809,7 +800,6 @@ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); - gtk_container_add(GTK_CONTAINER(sw), treeview); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(smile_selected_cb), dialog); g_signal_connect(G_OBJECT(treeview), "row_activated", G_CALLBACK(smiley_edit_cb), dialog); @@ -824,7 +814,7 @@ add_columns(treeview, dialog); populate_smiley_list(dialog); - return sw; + return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1); } static void refresh_list() diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkstatusbox.c --- a/pidgin/gtkstatusbox.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkstatusbox.c Mon Apr 25 20:13:05 2011 +0000 @@ -1312,15 +1312,19 @@ *width = allocation.width; hpolicy = vpolicy = GTK_POLICY_NEVER; - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window), - hpolicy, vpolicy); + g_object_set(G_OBJECT(status_box->scrolled_window), + "hscrollbar-policy", hpolicy, + "vscrollbar-policy", vpolicy, + NULL); gtk_widget_size_request (status_box->popup_frame, &popup_req); if (popup_req.width > *width) { hpolicy = GTK_POLICY_ALWAYS; - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window), - hpolicy, vpolicy); + g_object_set(G_OBJECT(status_box->scrolled_window), + "hscrollbar-policy", hpolicy, + "vscrollbar-policy", vpolicy, + NULL); gtk_widget_size_request (status_box->popup_frame, &popup_req); } @@ -1355,8 +1359,10 @@ { vpolicy = GTK_POLICY_ALWAYS; - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window), - hpolicy, vpolicy); + g_object_set(G_OBJECT(status_box->scrolled_window), + "hscrollbar-policy", hpolicy, + "vscrollbar-policy", vpolicy, + NULL); } } @@ -1799,19 +1805,6 @@ gtk_widget_show (status_box->popup_frame); - status_box->scrolled_window = gtk_scrolled_window_new (NULL, NULL); - - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (status_box->scrolled_window), - GTK_POLICY_NEVER, - GTK_POLICY_NEVER); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (status_box->scrolled_window), - GTK_SHADOW_NONE); - - gtk_widget_show (status_box->scrolled_window); - - gtk_container_add (GTK_CONTAINER (status_box->popup_frame), - status_box->scrolled_window); - status_box->tree_view = gtk_tree_view_new (); sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (status_box->tree_view)); gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE); @@ -1830,7 +1823,11 @@ gtk_tree_view_column_set_attributes(status_box->column, icon_rend, "stock-id", ICON_STOCK_COLUMN, NULL); gtk_tree_view_column_set_attributes(status_box->column, text_rend, "markup", TEXT_COLUMN, NULL); gtk_tree_view_column_set_attributes(status_box->column, emblem_rend, "stock-id", EMBLEM_COLUMN, "visible", EMBLEM_VISIBLE_COLUMN, NULL); - gtk_container_add(GTK_CONTAINER(status_box->scrolled_window), status_box->tree_view); + + status_box->scrolled_window = pidgin_make_scrollable(status_box->tree_view, GTK_POLICY_NEVER, GTK_POLICY_NEVER, GTK_SHADOW_NONE, -1, -1); + gtk_container_add (GTK_CONTAINER (status_box->popup_frame), + status_box->scrolled_window); + gtk_widget_show(status_box->tree_view); gtk_tree_view_set_search_column(GTK_TREE_VIEW(status_box->tree_view), TEXT_COLUMN); gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(status_box->tree_view), diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkutils.c Mon Apr 25 20:13:05 2011 +0000 @@ -244,12 +244,6 @@ gtk_widget_show(sep); } - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - gtk_widget_show(sw); - imhtml = gtk_imhtml_new(NULL, NULL); gtk_imhtml_set_editable(GTK_IMHTML(imhtml), editable); gtk_imhtml_set_format_functions(GTK_IMHTML(imhtml), GTK_IMHTML_ALL ^ GTK_IMHTML_IMAGE); @@ -266,7 +260,8 @@ } pidgin_setup_imhtml(imhtml); - gtk_container_add(GTK_CONTAINER(sw), imhtml); + sw = pidgin_make_scrollable(imhtml, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1); + gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); if (imhtml_ret != NULL) *imhtml_ret = imhtml; @@ -526,68 +521,35 @@ } static gpointer -aop_option_menu_get_selected(GtkWidget *optmenu, GtkWidget **p_item) +aop_option_menu_get_selected(GtkWidget *optmenu) { - GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)); - GtkWidget *item = gtk_menu_get_active(GTK_MENU(menu)); - if (p_item) - (*p_item) = item; - return item ? g_object_get_data(G_OBJECT(item), "aop_per_item_data") : NULL; + gpointer data = NULL; + GtkTreeIter iter; + + g_return_val_if_fail(optmenu != NULL, NULL); + + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(optmenu), &iter)) + gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(optmenu)), &iter, 2, &data, -1); + + return data; } static void aop_menu_cb(GtkWidget *optmenu, GCallback cb) { - GtkWidget *item; - gpointer per_item_data; - - per_item_data = aop_option_menu_get_selected(optmenu, &item); - if (cb != NULL) { - ((void (*)(GtkWidget *, gpointer, gpointer))cb)(item, per_item_data, g_object_get_data(G_OBJECT(optmenu), "user_data")); + ((void (*)(GtkWidget *, gpointer, gpointer))cb)(optmenu, + aop_option_menu_get_selected(optmenu), + g_object_get_data(G_OBJECT(optmenu), "user_data")); } } -static GtkWidget * -aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer per_item_data, const char *data) +static void +aop_option_menu_replace_menu(GtkWidget *optmenu, AopMenu *new_aop_menu) { - GtkWidget *item; - GtkWidget *hbox; - GtkWidget *image; - GtkWidget *label; - - item = gtk_menu_item_new(); - gtk_widget_show(item); - - hbox = gtk_hbox_new(FALSE, 4); - gtk_widget_show(hbox); - - /* Create the image */ - if (pixbuf == NULL) - image = gtk_image_new(); - else - image = gtk_image_new_from_pixbuf(pixbuf); - gtk_widget_show(image); - - if (sg) - gtk_size_group_add_widget(sg, image); - - /* Create the label */ - label = gtk_label_new (lbl); - gtk_widget_show (label); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - - gtk_container_add(GTK_CONTAINER(item), hbox); - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); - - g_object_set_data(G_OBJECT (item), data, per_item_data); - g_object_set_data(G_OBJECT (item), "aop_per_item_data", per_item_data); - - pidgin_set_accessible_label(item, label); - - return item; + gtk_combo_box_set_model(GTK_COMBO_BOX(optmenu), new_aop_menu->model); + gtk_combo_box_set_active(GTK_COMBO_BOX(optmenu), new_aop_menu->default_item); + g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", new_aop_menu, (GDestroyNotify)g_free); } static GdkPixbuf * @@ -628,16 +590,19 @@ static GtkWidget * aop_option_menu_new(AopMenu *aop_menu, GCallback cb, gpointer user_data) { - GtkWidget *optmenu; - - optmenu = gtk_option_menu_new(); + GtkWidget *optmenu = NULL; + GtkCellRenderer *cr = NULL; + + optmenu = gtk_combo_box_new(); gtk_widget_show(optmenu); - gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), aop_menu->menu); - - if (aop_menu->default_item != -1) - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), aop_menu->default_item); - - g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", aop_menu, (GDestroyNotify)g_free); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(optmenu), cr = gtk_cell_renderer_pixbuf_new(), FALSE); + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(optmenu), cr, "pixbuf", 0); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(optmenu), cr = gtk_cell_renderer_text_new(), TRUE); + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(optmenu), cr, "text", 1); + + aop_option_menu_replace_menu(optmenu, aop_menu); + if (aop_menu->default_item == -1) + gtk_combo_box_set_active(GTK_COMBO_BOX(optmenu), 0); g_object_set_data(G_OBJECT(optmenu), "user_data", user_data); g_signal_connect(G_OBJECT(optmenu), "changed", G_CALLBACK(aop_menu_cb), cb); @@ -646,32 +611,20 @@ } static void -aop_option_menu_replace_menu(GtkWidget *optmenu, AopMenu *new_aop_menu) -{ - if (gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu))) - gtk_option_menu_remove_menu(GTK_OPTION_MENU(optmenu)); - - gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), new_aop_menu->menu); - - if (new_aop_menu->default_item != -1) - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), new_aop_menu->default_item); - - g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", new_aop_menu, (GDestroyNotify)g_free); -} - -static void aop_option_menu_select_by_data(GtkWidget *optmenu, gpointer data) { - guint idx; - GList *llItr = NULL; - - for (idx = 0, llItr = GTK_MENU_SHELL(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))->children; - llItr != NULL; - llItr = llItr->next, idx++) { - if (data == g_object_get_data(G_OBJECT(llItr->data), "aop_per_item_data")) { - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), idx); - break; - } + GtkTreeModel *model; + GtkTreeIter iter; + gpointer iter_data; + model = gtk_combo_box_get_model(GTK_COMBO_BOX(optmenu)); + if (gtk_tree_model_get_iter_first(model, &iter)) { + do { + gtk_tree_model_get(model, &iter, 2, &iter_data, -1); + if (iter_data == data) { + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(optmenu), &iter); + return; + } + } while (gtk_tree_model_iter_next(model, &iter)); } } @@ -681,16 +634,17 @@ AopMenu *aop_menu = NULL; PurplePlugin *plugin; GdkPixbuf *pixbuf = NULL; - GtkSizeGroup *sg; + GtkTreeIter iter; + GtkListStore *ls; GList *p; const char *gtalk_name = NULL, *facebook_name = NULL; int i; + ls = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + aop_menu = g_malloc0(sizeof(AopMenu)); aop_menu->default_item = -1; - aop_menu->menu = gtk_menu_new(); - gtk_widget_show(aop_menu->menu); - sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + aop_menu->model = GTK_TREE_MODEL(ls); if (purple_find_prpl("prpl-jabber")) { gtalk_name = _("Google Talk"); @@ -706,14 +660,11 @@ if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0) { char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "16", "google-talk.png", NULL); - GtkWidget *item; - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); g_free(filename); - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), - item = aop_menu_item_new(sg, pixbuf, gtalk_name, "prpl-jabber", "protocol")); - g_object_set_data(G_OBJECT(item), "fakegoogle", GINT_TO_POINTER(1)); + gtk_list_store_append(ls, &iter); + gtk_list_store_set(ls, &iter, 0, pixbuf, 1, gtalk_name, 2, "prpl-jabber", -1); if (pixbuf) g_object_unref(pixbuf); @@ -725,14 +676,11 @@ if (facebook_name && strcmp(facebook_name, plugin->info->name) < 0) { char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "16", "facebook.png", NULL); - GtkWidget *item; - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); g_free(filename); - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), - item = aop_menu_item_new(sg, pixbuf, facebook_name, "prpl-jabber", "protocol")); - g_object_set_data(G_OBJECT(item), "fakefacebook", GINT_TO_POINTER(1)); + gtk_list_store_append(ls, &iter); + gtk_list_store_set(ls, &iter, 0, pixbuf, 1, facebook_name, 2, "prpl-jabber", -1); if (pixbuf) g_object_unref(pixbuf); @@ -743,8 +691,8 @@ pixbuf = pidgin_create_prpl_icon_from_prpl(plugin, PIDGIN_PRPL_ICON_SMALL, NULL); - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), - aop_menu_item_new(sg, pixbuf, plugin->info->name, plugin->info->id, "protocol")); + gtk_list_store_append(ls, &iter); + gtk_list_store_set(ls, &iter, 0, pixbuf, 1, plugin->info->name, 2, plugin->info->id, -1); if (pixbuf) g_object_unref(pixbuf); @@ -752,9 +700,6 @@ if (default_proto_id != NULL && !strcmp(plugin->info->id, default_proto_id)) aop_menu->default_item = i; } - - g_object_unref(sg); - return aop_menu; } @@ -768,13 +713,13 @@ const char * pidgin_protocol_option_menu_get_selected(GtkWidget *optmenu) { - return (const char *)aop_option_menu_get_selected(optmenu, NULL); + return (const char *)aop_option_menu_get_selected(optmenu); } PurpleAccount * pidgin_account_option_menu_get_selected(GtkWidget *optmenu) { - return (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL); + return (PurpleAccount *)aop_option_menu_get_selected(optmenu); } static AopMenu * @@ -786,7 +731,8 @@ GdkPixbuf *pixbuf = NULL; GList *list; GList *p; - GtkSizeGroup *sg; + GtkListStore *ls; + GtkTreeIter iter; int i; char buf[256]; @@ -795,11 +741,11 @@ else list = purple_connections_get_all(); + ls = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); + aop_menu = g_malloc0(sizeof(AopMenu)); aop_menu->default_item = -1; - aop_menu->menu = gtk_menu_new(); - gtk_widget_show(aop_menu->menu); - sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + aop_menu->model = GTK_TREE_MODEL(ls); for (p = list, i = 0; p != NULL; p = p->next, i++) { if (show_all) @@ -834,8 +780,8 @@ purple_account_get_protocol_name(account)); } - gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), - aop_menu_item_new(sg, pixbuf, buf, account, "account")); + gtk_list_store_append(ls, &iter); + gtk_list_store_set(ls, &iter, 0, pixbuf, 1, buf, 2, account, -1); if (pixbuf) g_object_unref(pixbuf); @@ -843,9 +789,6 @@ if (default_account && account == default_account) aop_menu->default_item = i; } - - g_object_unref(sg); - return aop_menu; } @@ -856,7 +799,7 @@ PurpleAccount *account; PurpleFilterAccountFunc filter_func; - account = (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL); + account = (PurpleAccount *)aop_option_menu_get_selected(optmenu); show_all = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(optmenu), "show_all")); filter_func = g_object_get_data(G_OBJECT(optmenu), "filter_func"); @@ -926,24 +869,6 @@ return optmenu; } -gboolean -pidgin_check_if_dir(const char *path, GtkFileSelection *filesel) -{ - char *dirname = NULL; - - if (g_file_test(path, G_FILE_TEST_IS_DIR)) { - /* append a / if needed */ - if (path[strlen(path) - 1] != G_DIR_SEPARATOR) { - dirname = g_strconcat(path, G_DIR_SEPARATOR_S, NULL); - } - gtk_file_selection_set_filename(filesel, (dirname != NULL) ? dirname : path); - g_free(dirname); - return TRUE; - } - - return FALSE; -} - void pidgin_setup_gtkspell(GtkTextView *textview) { @@ -1875,8 +1800,8 @@ group = gtk_menu_get_accel_group(GTK_MENU(menu)); if (group) { char *path = g_strdup_printf("%s/%s", - gtk_menu_item_get_accel_path(GTK_MENU_ITEM(menuitem)), - act->label); + gtk_menu_item_get_accel_path(GTK_MENU_ITEM(menuitem)), + act->label); gtk_menu_set_accel_path(GTK_MENU(submenu), path); g_free(path); gtk_menu_set_accel_group(GTK_MENU(submenu), group); @@ -2256,7 +2181,7 @@ gtk_widget_destroy(dialog->icon_filesel); g_free(filename); g_free(dialog); - } +} static void @@ -2890,7 +2815,7 @@ if (!widget) return "dim grey"; - style = gtk_widget_get_style(widget); + style = gtk_widget_get_style(widget); if (!style) return "dim grey"; @@ -2925,7 +2850,7 @@ GtkComboBoxText *ret = NULL; GtkWidget *the_entry = NULL; - ret = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + ret = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new_with_entry()); the_entry = gtk_entry_new(); gtk_container_add(GTK_CONTAINER(ret), the_entry); @@ -3496,6 +3421,29 @@ } #endif +GtkWidget * +pidgin_make_scrollable(GtkWidget *child, GtkPolicyType hscrollbar_policy, GtkPolicyType vscrollbar_policy, GtkShadowType shadow_type, int width, int height) +{ + GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); + + if (G_LIKELY(sw)) { + gtk_widget_show(sw); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), hscrollbar_policy, vscrollbar_policy); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), shadow_type); + if (width != -1 || height != -1) + gtk_widget_set_size_request(sw, width, height); + if (child) { + if (GTK_IS_SCROLLABLE(child)) + gtk_container_add(GTK_CONTAINER(sw), child); + else + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), child); + } + return sw; + } + + return child; +} + void pidgin_utils_init(void) { gtk_imhtml_class_register_protocol("http://", url_clicked_cb, link_context_menu); diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkutils.h --- a/pidgin/gtkutils.h Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkutils.h Mon Apr 25 20:13:05 2011 +0000 @@ -364,7 +364,7 @@ * Add autocompletion of screenames to an entry, supporting a filtering function. * * @param entry The GtkEntry on which to setup autocomplete. - * @param optmenu A menu for accounts, returned by gaim_gtk_account_option_menu_new(). + * @param optmenu A menu for accounts, returned by pidgin_account_option_menu_new(). * If @a optmenu is not @c NULL, it'll be updated when a username is chosen * from the autocomplete list. * @param filter_func A function for checking if an autocomplete entry @@ -830,6 +830,19 @@ GdkPixbuf *pidgin_pixbuf_from_imgstore(PurpleStoredImage *image); /** + * Add scrollbars to a widget + * @param widget The child widget + * @hscrollbar_policy Horizontal scrolling policy + * @vscrollbar_policy Vertical scrolling policy + * @shadow Shadow type + * @width Desired widget width, or -1 for default + * @height Desired widget height, or -1 for default + * + * @since 2.8.0 + */ +GtkWidget *pidgin_make_scrollable(GtkWidget *child, GtkPolicyType hscrollbar_policy, GtkPolicyType vscrollbar_policy, GtkShadowType shadow_type, int width, int height); + +/** * Initialize some utility functions. * * @since 2.6.0 diff -r a92f4cb593a4 -r 974722699032 pidgin/gtkwhiteboard.c --- a/pidgin/gtkwhiteboard.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/gtkwhiteboard.c Mon Apr 25 20:13:05 2011 +0000 @@ -360,7 +360,7 @@ cairo_t *cr; GdkWindow *window = gtk_widget_get_window(widget); GtkAllocation allocation; - + if (pixbuf) { cr = g_object_get_data(G_OBJECT(pixbuf), "cairo-context"); if (cr) @@ -369,11 +369,11 @@ } gtk_widget_get_allocation(widget, &allocation); - + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, - FALSE, gdk_visual_get_depth(GDK_VISUAL(window)), - allocation.width, allocation.height); - + FALSE, gdk_visual_get_depth(GDK_VISUAL(window)), + allocation.width, allocation.height); + gtkwb->pixbuf = pixbuf; cr = gdk_cairo_create(gtk_widget_get_window(widget)); @@ -708,10 +708,10 @@ GdkPixbuf *pixbuf = gtkwb->pixbuf; GtkWidget *drawing_area = gtkwb->drawing_area; cairo_t *cr = g_object_get_data(G_OBJECT(pixbuf), "cairo-context"); - GtkAllocation allocation; + GtkAllocation allocation; - gtk_widget_get_allocation(drawing_area, &allocation); - + gtk_widget_get_allocation(drawing_area, &allocation); + gdk_cairo_set_source_color(cr, >k_widget_get_style(drawing_area)->white); cairo_rectangle(cr, 0, 0, @@ -788,15 +788,15 @@ gtk_widget_destroy(dialog); /* Makes an icon from the whiteboard's canvas 'image' */ - pixbuf = gtkwb->pixbuf; - /* + pixbuf = gtkwb->pixbuf; +/* pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)(gtkwb->pixmap), gdk_drawable_get_colormap(gtkwb->pixmap), 0, 0, 0, 0, gtkwb->width, gtkwb->height); - */ +*/ if(gdk_pixbuf_save(pixbuf, filename, "jpeg", NULL, "quality", "100", NULL)) purple_debug_info("gtkwhiteboard", "File Saved...\n"); @@ -817,15 +817,15 @@ GdkPixbuf *pixbuf; /* Makes an icon from the whiteboard's canvas 'image' */ - pixbuf = gtkwb->pixbuf; - /* + pixbuf = gtkwb->pixbuf; +/* pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)(gtkwb->pixmap), gdk_drawable_get_colormap(gtkwb->pixmap), 0, 0, 0, 0, gtkwb->width, gtkwb->height); - */ +*/ gtk_window_set_icon((GtkWindow*)(gtkwb->window), pixbuf); } @@ -866,21 +866,20 @@ { GdkColor color; GtkColorSelectionDialog *dialog; - GtkWidget *ok_button; - + GtkWidget *ok_button; + dialog = (GtkColorSelectionDialog *)gtk_color_selection_dialog_new(_("Select color")); g_object_set_data(G_OBJECT(gtkwb->window), "colour-dialog", dialog); g_signal_connect(G_OBJECT(gtk_color_selection_dialog_get_color_selection(dialog)), - "color-changed", - G_CALLBACK(change_color_cb), gtkwb); + "color-changed", G_CALLBACK(change_color_cb), gtkwb); - /* +/* gtk_widget_destroy(dialog->cancel_button); gtk_widget_destroy(dialog->help_button); - */ - g_object_get(G_OBJECT(dialog), "ok-button", &ok_button, NULL); - +*/ + g_object_get(G_OBJECT(dialog), "ok-button", &ok_button, NULL); + g_signal_connect(G_OBJECT(ok_button), "clicked", G_CALLBACK(color_selection_dialog_destroy), gtkwb); @@ -888,7 +887,7 @@ pidgin_whiteboard_rgb24_to_rgb48(gtkwb->brush_color, &color); gtk_color_selection_set_current_color( - GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(dialog)), &color); + GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(dialog)), &color); gtk_widget_show_all(GTK_WIDGET(dialog)); } diff -r a92f4cb593a4 -r 974722699032 pidgin/minidialog.h --- a/pidgin/minidialog.h Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/minidialog.h Mon Apr 25 20:13:05 2011 +0000 @@ -148,7 +148,7 @@ /** Shortcut for setting a mini-dialog's custom icon via GObject properties. * @param mini_dialog a mini-dialog - * @param icon_name the pixbuf to use as a custom icon + * @param custom_icon the pixbuf to use as a custom icon */ void pidgin_mini_dialog_set_custom_icon(PidginMiniDialog *mini_dialog, GdkPixbuf *custom_icon); diff -r a92f4cb593a4 -r 974722699032 pidgin/pidginstock.c --- a/pidgin/pidginstock.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/pidginstock.c Mon Apr 25 20:13:05 2011 +0000 @@ -95,7 +95,7 @@ typedef struct { const char *name; - const char *dir; + const char *dir; const char *filename; gboolean microscopic; gboolean extra_small; diff -r a92f4cb593a4 -r 974722699032 pidgin/plugins/disco/gtkdisco.c --- a/pidgin/plugins/disco/gtkdisco.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/plugins/disco/gtkdisco.c Mon Apr 25 20:13:05 2011 +0000 @@ -648,15 +648,8 @@ pidgin_add_widget_to_vbox(GTK_BOX(vbox2), _("_Account:"), NULL, dialog->account_widget, TRUE, NULL); /* scrolled window */ - dialog->sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); + dialog->sw = pidgin_make_scrollable(NULL, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, 250); gtk_box_pack_start(GTK_BOX(vbox2), dialog->sw, TRUE, TRUE, 0); - gtk_widget_set_size_request(dialog->sw, -1, 250); - gtk_widget_show(dialog->sw); /* progress bar */ dialog->progress = gtk_progress_bar_new(); diff -r a92f4cb593a4 -r 974722699032 pidgin/plugins/gevolution/add_buddy_dialog.c --- a/pidgin/plugins/gevolution/add_buddy_dialog.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/plugins/gevolution/add_buddy_dialog.c Mon Apr 25 20:13:05 2011 +0000 @@ -430,7 +430,6 @@ { GevoAddBuddyDialog *dialog; GtkWidget *button; - GtkWidget *sw; GtkWidget *label; GtkWidget *vbox; GtkWidget *hbox; @@ -510,16 +509,6 @@ g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_cb), dialog); - /* Scrolled Window */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - gtk_widget_show(sw); - /* Create the list model for the treeview. */ dialog->model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, GDK_TYPE_PIXBUF, @@ -529,7 +518,9 @@ dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 0); gtk_widget_show(dialog->treeview); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); diff -r a92f4cb593a4 -r 974722699032 pidgin/plugins/gevolution/assoc-buddy.c --- a/pidgin/plugins/gevolution/assoc-buddy.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/plugins/gevolution/assoc-buddy.c Mon Apr 25 20:13:05 2011 +0000 @@ -314,7 +314,6 @@ { GevoAssociateBuddyDialog *dialog; GtkWidget *button; - GtkWidget *sw; GtkWidget *label; GtkWidget *vbox; GtkWidget *hbox; @@ -389,16 +388,6 @@ g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_cb), dialog); - /* Scrolled Window */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - gtk_widget_show(sw); - /* Create the list model for the treeview. */ dialog->model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER); @@ -407,7 +396,9 @@ dialog->treeview = gtk_tree_view_new_with_model( GTK_TREE_MODEL(dialog->model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(dialog->treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 0); gtk_widget_show(dialog->treeview); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); @@ -437,19 +428,10 @@ * User details */ - /* Scrolled Window */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_NEVER, - GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(expander), sw); - gtk_widget_show(sw); - /* Textview */ dialog->imhtml = gtk_imhtml_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(sw), dialog->imhtml); + gtk_container_add(GTK_CONTAINER(expander), + pidgin_make_scrollable(dialog->imhtml, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1)); gtk_widget_show(dialog->imhtml); /* Separator. */ diff -r a92f4cb593a4 -r 974722699032 pidgin/plugins/gevolution/gevolution.c --- a/pidgin/plugins/gevolution/gevolution.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/plugins/gevolution/gevolution.c Mon Apr 25 20:13:05 2011 +0000 @@ -417,7 +417,6 @@ GtkWidget *ret; GtkWidget *vbox; GtkWidget *label; - GtkWidget *sw; GtkWidget *treeview; GtkTreeViewColumn *column; GtkCellRenderer *renderer; @@ -439,17 +438,6 @@ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); gtk_widget_show(label); - /* Scrolled window */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); - gtk_widget_set_size_request(sw, 300, 300); - gtk_widget_show(sw); - /* Create the list model for the treeview. */ model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, @@ -458,7 +446,9 @@ /* Setup the treeview */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), treeview); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(treeview, GTK_POLICY_AUTO, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, 300, 300), + TRUE, TRUE, 0); gtk_widget_show(treeview); /* Setup the column */ diff -r a92f4cb593a4 -r 974722699032 pidgin/plugins/markerline.c --- a/pidgin/plugins/markerline.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/plugins/markerline.c Mon Apr 25 20:13:05 2011 +0000 @@ -42,7 +42,7 @@ #define PREF_CHATS PREF_PREFIX "/chats" static int -imhtml_expose_cb(GtkWidget *widget, GdkEventExpose *event, PidginConversation *gtkconv) +imhtml_expose_cb(GtkWidget *widget, cairo_t *cr, PidginConversation *gtkconv) { int y, last_y, offset; GdkRectangle visible_rect; @@ -51,6 +51,7 @@ int pad; PurpleConversation *conv = gtkconv->active_conv; PurpleConversationType type = purple_conversation_get_type(conv); + GdkColor red = {0, 0xffff, 0, 0}; if ((type == PURPLE_CONV_TYPE_CHAT && !purple_prefs_get_bool(PREF_CHATS)) || (type == PURPLE_CONV_TYPE_IM && !purple_prefs_get_bool(PREF_IMS))) @@ -76,20 +77,12 @@ gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_TEXT, 0, last_y, 0, &y); - /* TODO: port this to using Cairo - if (y >= event->area.y) - { - GdkColor red = {0, 0xffff, 0, 0}; - cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(event->window)); + gdk_cairo_set_source_color(cr, &red); + cairo_move_to(cr, 0.0, y + 0.5); + cairo_rel_line_to(cr, visible_rect.width, 0.0); + cairo_set_line_width(cr, 1.0); + cairo_stroke(cr); - gdk_cairo_set_source_color(cr, &red); - cairo_move_to(cr, 0.0, y + 0.5); - cairo_rel_line_to(cr, visible_rect.width, 0.0); - cairo_set_line_width(cr, 1.0); - cairo_stroke(cr); - cairo_destroy(cr); - } - */ return FALSE; } @@ -175,7 +168,7 @@ attach_to_gtkconv(PidginConversation *gtkconv, gpointer null) { detach_from_gtkconv(gtkconv, NULL); - g_signal_connect(G_OBJECT(gtkconv->imhtml), "expose_event", + g_signal_connect(G_OBJECT(gtkconv->imhtml), "draw", G_CALLBACK(imhtml_expose_cb), gtkconv); } diff -r a92f4cb593a4 -r 974722699032 pidgin/plugins/spellchk.c --- a/pidgin/plugins/spellchk.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/plugins/spellchk.c Mon Apr 25 20:13:05 2011 +0000 @@ -2156,7 +2156,7 @@ static GtkWidget * get_config_frame(PurplePlugin *plugin) { - GtkWidget *ret, *vbox, *win; + GtkWidget *ret, *vbox; GtkWidget *hbox; GtkWidget *button; GtkSizeGroup *sg; @@ -2173,15 +2173,6 @@ gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); gtk_widget_show(vbox); - win = gtk_scrolled_window_new(0, 0); - gtk_box_pack_start(GTK_BOX(vbox), win, TRUE, TRUE, 0); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(win), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(win), - GTK_POLICY_NEVER, - GTK_POLICY_ALWAYS); - gtk_widget_show(win); - tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE); gtk_widget_set_size_request(tree, -1, 200); @@ -2240,7 +2231,9 @@ gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), GTK_SELECTION_MULTIPLE); - gtk_container_add(GTK_CONTAINER(win), tree); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(tree, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), + TRUE, TRUE, 0); gtk_widget_show(tree); hbox = gtk_hbutton_box_new(); diff -r a92f4cb593a4 -r 974722699032 pidgin/plugins/xmppconsole.c --- a/pidgin/plugins/xmppconsole.c Wed Feb 02 23:26:42 2011 +0000 +++ b/pidgin/plugins/xmppconsole.c Mon Apr 25 20:13:05 2011 +0000 @@ -750,7 +750,6 @@ create_console(PurplePluginAction *action) { GtkWidget *vbox = gtk_vbox_new(FALSE, 6); - GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); GtkWidget *label; GtkTextBuffer *buffer; GtkWidget *toolbar; @@ -790,16 +789,13 @@ gtk_box_pack_start(GTK_BOX(console->hbox), console->dropdown, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(console->dropdown), "changed", G_CALLBACK(dropdown_changed_cb), NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - console->imhtml = gtk_imhtml_new(NULL, NULL); - gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); if (console->count == 0) gtk_imhtml_append_text(GTK_IMHTML(console->imhtml), _("Not connected to XMPP"), 0); - gtk_container_add(GTK_CONTAINER(sw), console->imhtml); + gtk_box_pack_start(GTK_BOX(vbox), + pidgin_make_scrollable(console->imhtml, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_ETCHED_IN, -1, -1), + TRUE, TRUE, 0); toolbar = gtk_toolbar_new(); button = gtk_tool_button_new(NULL, ""); @@ -816,21 +812,16 @@ gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - console->entry = gtk_imhtml_new(NULL, NULL); gtk_imhtml_set_whole_buffer_formatting_only(GTK_IMHTML(console->entry), TRUE); g_signal_connect(G_OBJECT(console->entry),"message_send", G_CALLBACK(message_send_cb), console); - gtk_box_pack_start(GTK_BOX(vbox), sw, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(sw), console->entry); + console->sw = pidgin_make_scrollable(console->entry, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_ETCHED_IN, -1, -1); + gtk_box_pack_start(GTK_BOX(vbox), console->sw, FALSE, FALSE, 0); gtk_imhtml_set_editable(GTK_IMHTML(console->entry), TRUE); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(console->entry)); g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(entry_changed_cb), NULL); - console->sw = sw; + entry_changed_cb(buffer, NULL); gtk_widget_show_all(console->window); diff -r a92f4cb593a4 -r 974722699032 po/ChangeLog --- a/po/ChangeLog Wed Feb 02 23:26:42 2011 +0000 +++ b/po/ChangeLog Mon Apr 25 20:13:05 2011 +0000 @@ -1,6 +1,39 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.7.11 + * Afrikaans translation updated (Friedel Wolff) + * Bengali translation updated (Jamil Ahmed) + * Chinese (Hong Kong) translation updated (Ambrose C. Li, Paladin R. + Liu) + * Chinese (Simplified) translation updated (Aron Xu) + * Chinese (Traditional) translation updated (Ambrose C. Li, Paladin R. + Liu) + * Czech translation updated (David Vachulka) + * Dutch translation updated (Gideon van Melle) + * Italian translation updated (Claudio Satriano) + * Norwegian Nynorsk translation updated (Yngve Spjeld Landro) + * Polish translation updated (Piotr Drąg) + * Romanian translation updated (Mişu Moldovan) + * Slovak translation updated (loptosko) + * Slovenian translation updated (Martin Srebotnjak) + * Ukrainian translation updated (Oleksandr Kovalenko) + version 2.7.10 + * Bengali translation updated (Jamil Ahmed) + * Chinese (Hong Kong) translation updated (Ambrose C. Li, Paladin R. + Liu) + * Chinese (Traditional) translation updated (Ambrose C. Li, Paladin R. + Liu) + * Czech translation updated (David Vachulka) + * Dutch translation updated (Gideon van Melle) + * Hebrew translation updated (Shalom Craimer) + * Norwegian Nynorsk translation updated (Yngve Spjeld Landro) + * Occitan translation updated (Yannig Marchegay) + * Polish translation updated (Piotr Drąg) + * Romanian translation updated (Mişu Moldovan) + * Russian translation updated (Антон Самохвалов) + * Spanish translation updated (Javier Fernández-Sanguino Peña) + * Ukrainian translation updated (Oleksandr Kovalenko) version 2.7.9 * Czech translation updated (David Vachulka) diff -r a92f4cb593a4 -r 974722699032 po/af.po --- a/po/af.po Wed Feb 02 23:26:42 2011 +0000 +++ b/po/af.po Mon Apr 25 20:13:05 2011 +0000 @@ -2,13 +2,13 @@ # Copyright (C) 2006-2010 # This file is distributed under the same license as the pidgin package. # Samuel Murray , 2007 -# F Wolff , 2006-2009, 2010. +# F Wolff , 2006-2009, 2010, 2011. msgid "" msgstr "" "Project-Id-Version: 2.7.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-12-19 13:33-0500\n" -"PO-Revision-Date: 2010-05-11 00:19+0200\n" +"POT-Creation-Date: 2011-03-10 02:28-0800\n" +"PO-Revision-Date: 2011-03-09 20:43+0200\n" "Last-Translator: F Wolff \n" "Language-Team: translate-discuss-af@lists.sourceforge.net\n" "Language: af\n" @@ -16,7 +16,8 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Virtaal 0.6.0\n" +"X-Generator: Virtaal 0.7.0-beta4\n" +"X-Project-Style: default\n" #. Translators may want to transliterate the name. #. It is not to be translated. @@ -61,9 +62,8 @@ msgid "Error" msgstr "Fout" -#, fuzzy msgid "Account was not modified" -msgstr "Rekening is nie bygevoeg nie" +msgstr "Rekening is nie gewysig nie" msgid "Account was not added" msgstr "Rekening is nie bygevoeg nie" @@ -2352,8 +2352,11 @@ "Pad om die lêers in te stoor\n" "(Verskaf gerus die volledige pad)" -msgid "Automatically reject from users not in buddy list" -msgstr "Weier outomaties vir gebruikers wat nie in die vriendelys is nie" +#, fuzzy +msgid "" +"When a file-transfer request arrives from a user who is\n" +"*not* on your buddy list:" +msgstr "Wanneer 'n versoek tot lêeroordrag vanaf %s aankom" msgid "" "Notify with a popup when an autoaccepted file transfer is complete\n" @@ -2365,6 +2368,10 @@ msgid "Create a new directory for each user" msgstr "Kies 'n nuwe gids vir elke gebruiker" +#, fuzzy +msgid "Escape the filenames" +msgstr "%s het die lêeroordrag gekanselleer" + msgid "Notes" msgstr "Notas" @@ -3205,9 +3212,7 @@ msgstr "UIN" #. first name -#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) ); #. optional information -#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title ); msgid "First Name" msgstr "Naam" @@ -3818,7 +3823,10 @@ msgid "Server requires plaintext authentication over an unencrypted stream" msgstr "Bediener vereis skoonteksstawing oor 'n ongeënkripteerde stroom" -#. This should never happen! +#. This happens when the server sends back jibberish +#. * in the "additional data with success" case. +#. * Seen with Wildfire 3.0.1. +#. msgid "Invalid response from server" msgstr "Ongeldige respons van die bediener" @@ -3960,7 +3968,6 @@ msgid "Postal Code" msgstr "Poskode" -#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email ); msgid "Country" msgstr "Land" @@ -6065,6 +6072,10 @@ msgid "Connecting..." msgstr "Koppel tans..." +#, fuzzy +msgid "The Display Name you entered is too short." +msgstr "Die naam wat gegee is, is ongeldig." + msgid "The PIN you entered has an invalid length [7-10]." msgstr "Die PIN wat gegee is, het 'n ongeldige lengte [7-10]." @@ -6135,35 +6146,6 @@ msgid "Retrieving User Information..." msgstr "Verkry tans gebruikerinligting..." -msgid "Loading menu..." -msgstr "Laai tans kieslys..." - -msgid "Status Message" -msgstr "Statusboodskap" - -#, fuzzy -msgid "Rejection Message" -msgstr "Ontvangde boodskappe" - -#. hidden number -msgid "Hidden Number" -msgstr "Versteekte nommer" - -#, fuzzy -msgid "Your MXit ID..." -msgstr "Yahoo-ID..." - -#. Configuration options -#. WAP server (reference: "libpurple/accountopt.h") -msgid "WAP Server" -msgstr "WAP-bediener" - -msgid "Connect via HTTP" -msgstr "Koppel via HTTP" - -msgid "Enable splash-screen popup" -msgstr "Aktiveer opsspring vir spatskerm" - #. you were kicked #, fuzzy msgid "You have been kicked from this MultiMX." @@ -6182,6 +6164,48 @@ msgid "You have invited" msgstr "Daar is pos!" +msgid "Loading menu..." +msgstr "Laai tans kieslys..." + +msgid "Status Message" +msgstr "Statusboodskap" + +#, fuzzy +msgid "Rejection Message" +msgstr "Ontvangde boodskappe" + +#. hidden number +msgid "Hidden Number" +msgstr "Versteekte nommer" + +#, fuzzy +msgid "No profile available" +msgstr "Nie beskikbaar nie" + +#, fuzzy +msgid "This contact does not have a profile." +msgstr "Hierdie rekening het nie e-pos geaktiveer nie." + +#, fuzzy +msgid "Your MXit ID..." +msgstr "Yahoo-ID..." + +#. contact is in Deleted, Rejected or None state +#, fuzzy +msgid "Re-Invite" +msgstr "Nooi uit" + +#. Configuration options +#. WAP server (reference: "libpurple/accountopt.h") +msgid "WAP Server" +msgstr "WAP-bediener" + +msgid "Connect via HTTP" +msgstr "Koppel via HTTP" + +msgid "Enable splash-screen popup" +msgstr "Aktiveer opsspring vir spatskerm" + #, fuzzy msgid "Last Online" msgstr "Aanlyn" @@ -7455,6 +7479,12 @@ msgid "You have been disconnected from chat room %s." msgstr "U is uit geselsiekamer %s ontkoppel." +msgid "The new formatting is invalid." +msgstr "Die nuwe formatering ongeldig." + +msgid "Username formatting can change only capitalization and whitespace." +msgstr "gebruikernaam-formatering kan net hoofletters en spasies verander." + msgid "Pop-Up Message" msgstr "Opspring-boodskap" @@ -7722,12 +7752,6 @@ msgid "ICQ Privacy Options" msgstr "ICQ-privaatheidopsies" -msgid "The new formatting is invalid." -msgstr "Die nuwe formatering ongeldig." - -msgid "Username formatting can change only capitalization and whitespace." -msgstr "gebruikernaam-formatering kan net hoofletters en spasies verander." - msgid "Change Address To:" msgstr "Verander adres na:" @@ -7839,75 +7863,6 @@ "kitsboodskapprente. Omdat u IP-adres bekend gemaak sal word, kan dit 'n " "privaatheidrisiko wees." -msgid "Invalid SNAC" -msgstr "Ongeldige SNAC" - -msgid "Server rate limit exceeded" -msgstr "" - -msgid "Client rate limit exceeded" -msgstr "" - -msgid "Service unavailable" -msgstr "Diens nie beskikbaar nie" - -msgid "Service not defined" -msgstr "Diens nie gedefinieer nie" - -msgid "Obsolete SNAC" -msgstr "Verouderde SNAC" - -msgid "Not supported by host" -msgstr "Word nie deur gasheer ondersteun nie" - -msgid "Not supported by client" -msgstr "Word nie deur kliënt ondersteun nie" - -msgid "Refused by client" -msgstr "Deur kliënt geweier" - -msgid "Reply too big" -msgstr "Antwoord te groot" - -msgid "Responses lost" -msgstr "Response verloor" - -msgid "Request denied" -msgstr "Versoek geweier" - -msgid "Busted SNAC payload" -msgstr "Gebreekte SNAC-afvoer" - -msgid "Insufficient rights" -msgstr "Onvoldoende regte" - -msgid "In local permit/deny" -msgstr "In plaaslike toelaat/weier" - -msgid "Warning level too high (sender)" -msgstr "Waarskuwingvlak té hoog (sender)" - -msgid "Warning level too high (receiver)" -msgstr "Waarskuwingvlak te hoog (ontvanger)" - -msgid "User temporarily unavailable" -msgstr "Gebruiker tydelik nie beskikbaar nie" - -msgid "No match" -msgstr "Geen passing nie" - -msgid "List overflow" -msgstr "Lysoorvloed" - -msgid "Request ambiguous" -msgstr "Versoek dubbelsinnig" - -msgid "Queue full" -msgstr "Tou vol" - -msgid "Not while on AOL" -msgstr "Nie terwyl op AOL nie" - #. Label msgid "Buddy Icon" msgstr "Vriendikoon" @@ -8026,6 +7981,75 @@ msgid "Capabilities" msgstr "Vermoëns" +msgid "Invalid SNAC" +msgstr "Ongeldige SNAC" + +msgid "Server rate limit exceeded" +msgstr "" + +msgid "Client rate limit exceeded" +msgstr "" + +msgid "Service unavailable" +msgstr "Diens nie beskikbaar nie" + +msgid "Service not defined" +msgstr "Diens nie gedefinieer nie" + +msgid "Obsolete SNAC" +msgstr "Verouderde SNAC" + +msgid "Not supported by host" +msgstr "Word nie deur gasheer ondersteun nie" + +msgid "Not supported by client" +msgstr "Word nie deur kliënt ondersteun nie" + +msgid "Refused by client" +msgstr "Deur kliënt geweier" + +msgid "Reply too big" +msgstr "Antwoord te groot" + +msgid "Responses lost" +msgstr "Response verloor" + +msgid "Request denied" +msgstr "Versoek geweier" + +msgid "Busted SNAC payload" +msgstr "Gebreekte SNAC-afvoer" + +msgid "Insufficient rights" +msgstr "Onvoldoende regte" + +msgid "In local permit/deny" +msgstr "In plaaslike toelaat/weier" + +msgid "Warning level too high (sender)" +msgstr "Waarskuwingvlak té hoog (sender)" + +msgid "Warning level too high (receiver)" +msgstr "Waarskuwingvlak te hoog (ontvanger)" + +msgid "User temporarily unavailable" +msgstr "Gebruiker tydelik nie beskikbaar nie" + +msgid "No match" +msgstr "Geen passing nie" + +msgid "List overflow" +msgstr "Lysoorvloed" + +msgid "Request ambiguous" +msgstr "Versoek dubbelsinnig" + +msgid "Queue full" +msgstr "Tou vol" + +msgid "Not while on AOL" +msgstr "Nie terwyl op AOL nie" + #. Translators: This string is a menu option that, if selected, will cause #. you to appear online to the chosen user even when your status is set to #. Invisible. @@ -8642,14 +8666,14 @@ msgid "Select Server" msgstr "Kies bediener" -msgid "QQ2005" -msgstr "QQ2005" +msgid "QQ2008" +msgstr "QQ2008" msgid "QQ2007" msgstr "QQ2007" -msgid "QQ2008" -msgstr "QQ2008" +msgid "QQ2005" +msgstr "QQ2005" msgid "Connect by TCP" msgstr "Koppel met TCP" @@ -8663,6 +8687,10 @@ msgid "Show chat room when msg comes" msgstr "" +#, fuzzy +msgid "Use default font" +msgstr "Gebruik die stelselverstek" + msgid "Keep alive interval (seconds)" msgstr "Wakkerhou-interval (sekondes)" @@ -12202,9 +12230,6 @@ msgid "Fatal Error" msgstr "Fatale fout" -msgid "bug master" -msgstr "goggameester" - msgid "artist" msgstr "kunstenaar" @@ -12386,6 +12411,10 @@ msgid "Maithili" msgstr "Swahili" +#, fuzzy +msgid "Meadow Mari" +msgstr "Nuwe pos" + msgid "Macedonian" msgstr "Masedonies" @@ -13232,6 +13261,13 @@ msgid "New Pounces" msgstr "Nuwe vriendwagte" +#. Translators: Make sure you translate "Dismiss" differently than +#. "close"! This string is used in the "You have pounced" dialog +#. that appears when one of your Buddy Pounces is triggered. In +#. this context "Dismiss" means "I acknowledge that I've seen that +#. this pounce was triggered--remove it from this list." Translating +#. it as "Remove" is acceptable if you can't think of a more precise +#. word. msgid "Dismiss" msgstr "" @@ -15492,6 +15528,12 @@ msgid "You do not have permission to uninstall this application." msgstr "U het nie toestemming om hierdie toepassing te verwyder nie." +#~ msgid "Automatically reject from users not in buddy list" +#~ msgstr "Weier outomaties vir gebruikers wat nie in die vriendelys is nie" + +#~ msgid "bug master" +#~ msgstr "goggameester" + #~ msgid "Transfer was closed." #~ msgstr "Oordrag is gesluit." diff -r a92f4cb593a4 -r 974722699032 po/bn.po --- a/po/bn.po Wed Feb 02 23:26:42 2011 +0000 +++ b/po/bn.po Mon Apr 25 20:13:05 2011 +0000 @@ -7,14 +7,14 @@ # Samia Niamatullah , 2009. # Sadia Afroz , 2010. # Ummey Salma , 2010. -# Israt Jahan , 2008-2009, 2010. +# Israt Jahan , 2008-2009, 2010, 2011. # msgid "" msgstr "" "Project-Id-Version: bn\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-12-19 20:34-0500\n" -"PO-Revision-Date: 2010-12-19 13:37+0600\n" +"POT-Creation-Date: 2011-03-10 01:22-0800\n" +"PO-Revision-Date: 2011-03-06 13:37+0600\n" "Last-Translator: israt \n" "Language-Team: Bengali \n" "Language: bn\n" @@ -2466,8 +2466,12 @@ "ফাইল সংরক্ষণের ‍‍পাথ\n" "(অনুগ্রহ করে সম্পূর্ণ পাথ প্রদান করুন)" -msgid "Automatically reject from users not in buddy list" -msgstr "বন্ধু তালিকার বহির্ভূত ব্যবহারকারী থেকে স্বয়ংক্রিয় ভাবে বাতিল করা হবে" +msgid "" +"When a file-transfer request arrives from a user who is\n" +"*not* on your buddy list:" +msgstr "" +"যখন একজন ব্যবহারকারী থেকে ফাইল স্থানান্তরের অনুরোধ আসে\n" +" যা আপনার বন্ধু তালিকায় *নেই*:" # tithi msgid "" @@ -2480,6 +2484,10 @@ msgid "Create a new directory for each user" msgstr "প্রত্যেক ব্যবহারকারীর জন্য একটি নতুন ডিরেক্টরি তৈরি করা হবে" +# Translated by sadia +msgid "Escape the filenames" +msgstr "ফাইলনাম এড়িয়ে যাওয়া" + msgid "Notes" msgstr "নোট" @@ -3357,9 +3365,7 @@ msgstr "UIN" #. first name -#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) ); #. optional information -#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title ); msgid "First Name" msgstr "প্রথম নাম" @@ -3993,7 +3999,10 @@ msgid "Server requires plaintext authentication over an unencrypted stream" msgstr "একটি এনক্রিপশনবিহীন স্ট্রীমে সার্ভারের সরল-টেক্সট প্রমাণীকরণ প্রয়োজন" -#. This should never happen! +#. This happens when the server sends back jibberish +#. * in the "additional data with success" case. +#. * Seen with Wildfire 3.0.1. +#. msgid "Invalid response from server" msgstr "সার্ভার থেকে অকার্যকর উত্তর" @@ -4145,7 +4154,6 @@ msgid "Postal Code" msgstr "পোস্টাল কোড" -#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email ); msgid "Country" msgstr "দেশ" @@ -6505,6 +6513,14 @@ # tithi # # +# Translated by sadia +#, fuzzy +msgid "The Display Name you entered is too short." +msgstr "আপনি যে নাম প্রবেশ করেছেন তা অকার্যকর।" + +# tithi +# +# # # # Translated by sadia @@ -6605,6 +6621,22 @@ msgid "Retrieving User Information..." msgstr "ব্যবহারকারীর তথ্য খুঁজে আনা হচ্ছে..." +# Kick = তিরস্কার +# OR পদাঘাত +#. you were kicked +msgid "You have been kicked from this MultiMX." +msgstr "MultiMX হতে আপনাকে তিরস্কার করা হয়েছে।" + +msgid "was kicked" +msgstr "তিরস্কার করা হয়েছে" + +msgid "_Room Name:" +msgstr "আসরের নাম (_R):" + +#. Display system message in chat window +msgid "You have invited" +msgstr "আপনাকে আমন্ত্রণ জানানো হয়েছে" + # Translated by sadia msgid "Loading menu..." msgstr "মেনু লোড করা হচ্ছে..." @@ -6622,10 +6654,24 @@ msgid "Hidden Number" msgstr "লুকানো সংখ্যা" +#, fuzzy +msgid "No profile available" +msgstr "অনুপস্থিত" + +# tithi +#, fuzzy +msgid "This contact does not have a profile." +msgstr "এই অ্যাকাউন্টটির কোন ইমেইল সক্রিয় নেই।" + # snigdha msgid "Your MXit ID..." msgstr "আপনার MXit ID..." +#. contact is in Deleted, Rejected or None state +#, fuzzy +msgid "Re-Invite" +msgstr "আমন্ত্রণ জানান" + # Translated by sadia #. Configuration options #. WAP server (reference: "libpurple/accountopt.h") @@ -6640,22 +6686,6 @@ msgid "Enable splash-screen popup" msgstr "স্প্ল্যাশ স্ক্রীন পপ আপ সক্রিয় করা হবে" -# Kick = তিরস্কার -# OR পদাঘাত -#. you were kicked -msgid "You have been kicked from this MultiMX." -msgstr "MultiMX হতে আপনাকে তিরস্কার করা হয়েছে।" - -msgid "was kicked" -msgstr "তিরস্কার করা হয়েছে" - -msgid "_Room Name:" -msgstr "আসরের নাম (_R):" - -#. Display system message in chat window -msgid "You have invited" -msgstr "আপনাকে আমন্ত্রণ জানানো হয়েছে" - msgid "Last Online" msgstr "শেষ যখন অনলাইনে" @@ -8116,6 +8146,13 @@ msgid "You have been disconnected from chat room %s." msgstr "আপনাকে %s আড্ডার আসর থেকে বিচ্ছিন্ন করা হয়েছে।" +msgid "The new formatting is invalid." +msgstr "নতুন বিন্যাসটি অকার্যকর।" + +# tithi +msgid "Username formatting can change only capitalization and whitespace." +msgstr "ব্যবহারকারীর নামের শুধুমাত্র অক্ষরের ছাঁদ এবং ফাঁকা জায়গা পরিবর্তন করা যাবে।" + msgid "Pop-Up Message" msgstr "পপ-আপ বার্তা" @@ -8416,13 +8453,6 @@ msgid "ICQ Privacy Options" msgstr "ICQ গোপনীয়তার অপশন" -msgid "The new formatting is invalid." -msgstr "নতুন বিন্যাসটি অকার্যকর।" - -# tithi -msgid "Username formatting can change only capitalization and whitespace." -msgstr "ব্যবহারকারীর নামের শুধুমাত্র অক্ষরের ছাঁদ এবং ফাঁকা জায়গা পরিবর্তন করা যাবে।" - # tithi msgid "Change Address To:" msgstr "ঠিকানা পরিবর্তন করুন:" @@ -8546,91 +8576,6 @@ "এটির জন্য দুটি কম্পিউটারের মধ্যে সরাসরি সংযোগ প্রয়োজন যা কিনা IM এর ছবির জন্য " "আবশ্যক। যেহেতু আপনার IP ঠিকানা প্রকাশিত হবে, তাই এতে গোপনীয়তায় ঝুঁকি থাকতে পারে।" -msgid "Invalid SNAC" -msgstr "অকার্যকর SNAC" - -msgid "Server rate limit exceeded" -msgstr "সার্ভার হারের সীমা পেরিয়ে গেছে" - -msgid "Client rate limit exceeded" -msgstr "ক্লায়েন্ট হারের সীমা পেরিয়ে গেছে" - -msgid "Service unavailable" -msgstr "সার্ভিস বিদ্যমান নয়" - -# tithi -msgid "Service not defined" -msgstr "সেবা নির্ধারিত নয়" - -# tithi -msgid "Obsolete SNAC" -msgstr "অপ্রচলিত SNAC" - -# tithi -msgid "Not supported by host" -msgstr "হোস্ট দ্বারা সমর্থিত নয়" - -# tithi -msgid "Not supported by client" -msgstr "ক্লায়েন্ট দ্বারা সমর্থিত নয়" - -# tithi -msgid "Refused by client" -msgstr "ক্লায়েন্ট দ্বারা প্রত্যাখ্যাত" - -# tithi -msgid "Reply too big" -msgstr "অতিরিক্ত বড় উত্তর" - -# tithi -msgid "Responses lost" -msgstr "প্রতিক্রিয়া হারিয়ে গেছে" - -msgid "Request denied" -msgstr "অনুরোধ প্রত্যাখ্যাত" - -# tithi -msgid "Busted SNAC payload" -msgstr "ব্যর্থ SNAC পেলোড" - -# tithi -msgid "Insufficient rights" -msgstr "অপর্যাপ্ত অধিকার" - -# tithi -msgid "In local permit/deny" -msgstr "স্থানীয় অনুমতি/অস্বীকারে" - -# tithi -msgid "Warning level too high (sender)" -msgstr "সতর্কতা স্তর খুব উচ্চ (প্রেরক)" - -# tithi -msgid "Warning level too high (receiver)" -msgstr "সতর্কতা স্তর খুব উচ্চ (গ্রাহক)" - -# tithi -msgid "User temporarily unavailable" -msgstr "ব্যবহারকারীকে সাময়িকভাবে পাওয়া যায়না" - -# tithi -msgid "No match" -msgstr "কোনো মিল নেই" - -# tithi -msgid "List overflow" -msgstr "লিস্ট ওভার‌ফ্লো" - -msgid "Request ambiguous" -msgstr "অনুরোধ অস্পষ্ট" - -# tithi -msgid "Queue full" -msgstr "কিউ পরিপূর্ণ" - -msgid "Not while on AOL" -msgstr "AOL এ থাকা অবস্থায় নয়" - #. Label msgid "Buddy Icon" msgstr "বন্ধু আইকন" @@ -8767,6 +8712,91 @@ msgid "Capabilities" msgstr "ক্ষমতা" +msgid "Invalid SNAC" +msgstr "অকার্যকর SNAC" + +msgid "Server rate limit exceeded" +msgstr "সার্ভার হারের সীমা পেরিয়ে গেছে" + +msgid "Client rate limit exceeded" +msgstr "ক্লায়েন্ট হারের সীমা পেরিয়ে গেছে" + +msgid "Service unavailable" +msgstr "সার্ভিস বিদ্যমান নয়" + +# tithi +msgid "Service not defined" +msgstr "সেবা নির্ধারিত নয়" + +# tithi +msgid "Obsolete SNAC" +msgstr "অপ্রচলিত SNAC" + +# tithi +msgid "Not supported by host" +msgstr "হোস্ট দ্বারা সমর্থিত নয়" + +# tithi +msgid "Not supported by client" +msgstr "ক্লায়েন্ট দ্বারা সমর্থিত নয়" + +# tithi +msgid "Refused by client" +msgstr "ক্লায়েন্ট দ্বারা প্রত্যাখ্যাত" + +# tithi +msgid "Reply too big" +msgstr "অতিরিক্ত বড় উত্তর" + +# tithi +msgid "Responses lost" +msgstr "প্রতিক্রিয়া হারিয়ে গেছে" + +msgid "Request denied" +msgstr "অনুরোধ প্রত্যাখ্যাত" + +# tithi +msgid "Busted SNAC payload" +msgstr "ব্যর্থ SNAC পেলোড" + +# tithi +msgid "Insufficient rights" +msgstr "অপর্যাপ্ত অধিকার" + +# tithi +msgid "In local permit/deny" +msgstr "স্থানীয় অনুমতি/অস্বীকারে" + +# tithi +msgid "Warning level too high (sender)" +msgstr "সতর্কতা স্তর খুব উচ্চ (প্রেরক)" + +# tithi +msgid "Warning level too high (receiver)" +msgstr "সতর্কতা স্তর খুব উচ্চ (গ্রাহক)" + +# tithi +msgid "User temporarily unavailable" +msgstr "ব্যবহারকারীকে সাময়িকভাবে পাওয়া যায়না" + +# tithi +msgid "No match" +msgstr "কোনো মিল নেই" + +# tithi +msgid "List overflow" +msgstr "লিস্ট ওভার‌ফ্লো" + +msgid "Request ambiguous" +msgstr "অনুরোধ অস্পষ্ট" + +# tithi +msgid "Queue full" +msgstr "কিউ পরিপূর্ণ" + +msgid "Not while on AOL" +msgstr "AOL এ থাকা অবস্থায় নয়" + # tithi #. Translators: This string is a menu option that, if selected, will cause #. you to appear online to the chosen user even when your status is set to @@ -9420,16 +9450,16 @@ msgstr "সার্ভার নির্বাচন" # tithi -msgid "QQ2005" -msgstr "QQ2005" +msgid "QQ2008" +msgstr "QQ2008" # tithi msgid "QQ2007" msgstr "QQ2007" # tithi -msgid "QQ2008" -msgstr "QQ2008" +msgid "QQ2005" +msgstr "QQ2005" msgid "Connect by TCP" msgstr "TCP দ্বারা সংযোগ করা হবে" @@ -9443,6 +9473,9 @@ msgid "Show chat room when msg comes" msgstr "বার্তা আসলে আড্ডার আসর প্রদর্শিত হবে " +msgid "Use default font" +msgstr "পূর্বনির্ধারিত ফন্টের ব্যবহার" + # fix me tithi msgid "Keep alive interval (seconds)" msgstr "সক্রিয় রাখার সময়ের ব্যবধান (সেকেন্ড)" @@ -13272,10 +13305,6 @@ msgid "Fatal Error" msgstr "মারাত্মক ত্রুটি" -# tithi -msgid "bug master" -msgstr "বাগ মাস্টার" - msgid "artist" msgstr "শিল্পী" @@ -13472,6 +13501,9 @@ msgid "Maithili" msgstr "মৈথিলি" +msgid "Meadow Mari" +msgstr "মিইডো মারি" + msgid "Macedonian" msgstr "ম্যাসেডনিয়" @@ -16808,6 +16840,13 @@ msgid "You do not have permission to uninstall this application." msgstr "আপনার এই অ্যাপ্লিকেশনটি আনইন্সটল করার অনুমতি নেই।" +#~ msgid "Automatically reject from users not in buddy list" +#~ msgstr "বন্ধু তালিকার বহির্ভূত ব্যবহারকারী থেকে স্বয়ংক্রিয় ভাবে বাতিল করা হবে" + +# tithi +#~ msgid "bug master" +#~ msgstr "বাগ মাস্টার" + #~ msgid "An error occurred on the in-band bytestream transfer\n" #~ msgstr "ইন-ব্যান্ড বাইটস্ট্রিম বিনিময়ে ত্রুটি হয়েছে\n" diff -r a92f4cb593a4 -r 974722699032 po/cs.po --- a/po/cs.po Wed Feb 02 23:26:42 2011 +0000 +++ b/po/cs.po Mon Apr 25 20:13:05 2011 +0000 @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: pidgin VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-12-26 22:11-0500\n" -"PO-Revision-Date: 2010-12-21 09:08+0100\n" +"POT-Creation-Date: 2011-03-10 01:35-0800\n" +"PO-Revision-Date: 2011-03-06 17:30+0100\n" "Last-Translator: David Vachulka \n" "Language-Team: Czech \n" "Language: cs\n" @@ -2328,8 +2328,12 @@ "Cesta, kam ukládat soubory\n" "(Zadejte prosím plnou cestu)" -msgid "Automatically reject from users not in buddy list" -msgstr "Automaticky odmítat od uživatelů, kteří nejsou na seznamu kamarádů" +msgid "" +"When a file-transfer request arrives from a user who is\n" +"*not* on your buddy list:" +msgstr "" +"Když přijde požadavek na přenos souboru od někoho,\n" +"kdo není v seznamu kamarádů:" msgid "" "Notify with a popup when an autoaccepted file transfer is complete\n" @@ -2342,6 +2346,9 @@ msgid "Create a new directory for each user" msgstr "Vytvořit nový adresář pro každého uživatele" +msgid "Escape the filenames" +msgstr "Upravit jména souborů" + msgid "Notes" msgstr "Poznámky" @@ -3180,9 +3187,7 @@ msgstr "UIN" #. first name -#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) ); #. optional information -#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title ); msgid "First Name" msgstr "Křestní jméno" @@ -3793,7 +3798,10 @@ msgid "Server requires plaintext authentication over an unencrypted stream" msgstr "Server vyžaduje textovou autentizaci v nešifrovaném proudu" -#. This should never happen! +#. This happens when the server sends back jibberish +#. * in the "additional data with success" case. +#. * Seen with Wildfire 3.0.1. +#. msgid "Invalid response from server" msgstr "Neplatná odpověď od serveru" @@ -3934,7 +3942,6 @@ msgid "Postal Code" msgstr "PSČ" -#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email ); msgid "Country" msgstr "Země" @@ -6006,6 +6013,9 @@ msgid "Connecting..." msgstr "Připojování..." +msgid "The Display Name you entered is too short." +msgstr "Zadané jméno pro zobrazení je příliš krátké." + msgid "The PIN you entered has an invalid length [7-10]." msgstr "Zadaný PIN má neplatnou délku [7-10]." @@ -6074,33 +6084,6 @@ msgid "Retrieving User Information..." msgstr "Získávám informace o uživateli..." -msgid "Loading menu..." -msgstr "Načítám menu..." - -msgid "Status Message" -msgstr "Stavová zpráva" - -msgid "Rejection Message" -msgstr "Zamítnutí zprávy" - -#. hidden number -msgid "Hidden Number" -msgstr "Skryté číslo" - -msgid "Your MXit ID..." -msgstr "Vaše MXit ID..." - -#. Configuration options -#. WAP server (reference: "libpurple/accountopt.h") -msgid "WAP Server" -msgstr "WAP Server" - -msgid "Connect via HTTP" -msgstr "Připojit se pomocí HTTP" - -msgid "Enable splash-screen popup" -msgstr "Povolit zobrazení spouštěcí obrazovky" - #. you were kicked msgid "You have been kicked from this MultiMX." msgstr "Byl jste vykopnut z MultiMX." @@ -6115,6 +6098,43 @@ msgid "You have invited" msgstr "Přišlo vám pozvání" +msgid "Loading menu..." +msgstr "Načítám menu..." + +msgid "Status Message" +msgstr "Stavová zpráva" + +msgid "Rejection Message" +msgstr "Zamítnutí zprávy" + +#. hidden number +msgid "Hidden Number" +msgstr "Skryté číslo" + +msgid "No profile available" +msgstr "Není dostupný profil" + +msgid "This contact does not have a profile." +msgstr "Tento kontakt nemá profil." + +msgid "Your MXit ID..." +msgstr "Vaše MXit ID..." + +#. contact is in Deleted, Rejected or None state +msgid "Re-Invite" +msgstr "Znovu pozvat" + +#. Configuration options +#. WAP server (reference: "libpurple/accountopt.h") +msgid "WAP Server" +msgstr "WAP Server" + +msgid "Connect via HTTP" +msgstr "Připojit se pomocí HTTP" + +msgid "Enable splash-screen popup" +msgstr "Povolit zobrazení spouštěcí obrazovky" + msgid "Last Online" msgstr "Naposledy připojen" @@ -7394,6 +7414,12 @@ msgid "You have been disconnected from chat room %s." msgstr "Byl jste odpojen z místnosti chatu %s." +msgid "The new formatting is invalid." +msgstr "Nové formátování je neplatné." + +msgid "Username formatting can change only capitalization and whitespace." +msgstr "Formátování jména uživatele může změnit jen velikost písmen a mezery." + msgid "Pop-Up Message" msgstr "Vyskakovací zpráva" @@ -7664,12 +7690,6 @@ msgid "ICQ Privacy Options" msgstr "Možnosti soukromí ICQ" -msgid "The new formatting is invalid." -msgstr "Nové formátování je neplatné." - -msgid "Username formatting can change only capitalization and whitespace." -msgstr "Formátování jména uživatele může změnit jen velikost písmen a mezery." - msgid "Change Address To:" msgstr "Změnit adresu na:" @@ -7776,75 +7796,6 @@ "Images. Protože bude odkryta vaše IP adresa, dá se to považovat za riziko " "pro soukromí." -msgid "Invalid SNAC" -msgstr "Neplatné SNAC" - -msgid "Server rate limit exceeded" -msgstr "Překročen limit poměru serveru" - -msgid "Client rate limit exceeded" -msgstr "Překročen limit poměru klienta" - -msgid "Service unavailable" -msgstr "Služba nedostupná" - -msgid "Service not defined" -msgstr "Služba nedefinována" - -msgid "Obsolete SNAC" -msgstr "Zastaralé SNAC" - -msgid "Not supported by host" -msgstr "Nepodporováno hostitelem" - -msgid "Not supported by client" -msgstr "Nepodporováno klientem" - -msgid "Refused by client" -msgstr "Odmítnuto klientem" - -msgid "Reply too big" -msgstr "Odpověď příliš velká" - -msgid "Responses lost" -msgstr "Odpovědi ztraceny" - -msgid "Request denied" -msgstr "Požadavek zamítnut" - -msgid "Busted SNAC payload" -msgstr "Poškozená data SNAC" - -msgid "Insufficient rights" -msgstr "Nedostatečná oprávnění" - -msgid "In local permit/deny" -msgstr "V místním povolit/zakázat" - -msgid "Warning level too high (sender)" -msgstr "Hladina varování příliš vysoká (odeslání)" - -msgid "Warning level too high (receiver)" -msgstr "Hladina varování příliš vysoká (příjem)" - -msgid "User temporarily unavailable" -msgstr "Uživatel dočasně nedostupný" - -msgid "No match" -msgstr "Žádná shoda" - -msgid "List overflow" -msgstr "Přetečení seznamu" - -msgid "Request ambiguous" -msgstr "Požadavek nejednoznačný" - -msgid "Queue full" -msgstr "Fronta plná" - -msgid "Not while on AOL" -msgstr "Ne když na AOL" - #. Label msgid "Buddy Icon" msgstr "Ikona kamaráda" @@ -7963,6 +7914,75 @@ msgid "Capabilities" msgstr "Schopnosti" +msgid "Invalid SNAC" +msgstr "Neplatné SNAC" + +msgid "Server rate limit exceeded" +msgstr "Překročen limit poměru serveru" + +msgid "Client rate limit exceeded" +msgstr "Překročen limit poměru klienta" + +msgid "Service unavailable" +msgstr "Služba nedostupná" + +msgid "Service not defined" +msgstr "Služba nedefinována" + +msgid "Obsolete SNAC" +msgstr "Zastaralé SNAC" + +msgid "Not supported by host" +msgstr "Nepodporováno hostitelem" + +msgid "Not supported by client" +msgstr "Nepodporováno klientem" + +msgid "Refused by client" +msgstr "Odmítnuto klientem" + +msgid "Reply too big" +msgstr "Odpověď příliš velká" + +msgid "Responses lost" +msgstr "Odpovědi ztraceny" + +msgid "Request denied" +msgstr "Požadavek zamítnut" + +msgid "Busted SNAC payload" +msgstr "Poškozená data SNAC" + +msgid "Insufficient rights" +msgstr "Nedostatečná oprávnění" + +msgid "In local permit/deny" +msgstr "V místním povolit/zakázat" + +msgid "Warning level too high (sender)" +msgstr "Hladina varování příliš vysoká (odeslání)" + +msgid "Warning level too high (receiver)" +msgstr "Hladina varování příliš vysoká (příjem)" + +msgid "User temporarily unavailable" +msgstr "Uživatel dočasně nedostupný" + +msgid "No match" +msgstr "Žádná shoda" + +msgid "List overflow" +msgstr "Přetečení seznamu" + +msgid "Request ambiguous" +msgstr "Požadavek nejednoznačný" + +msgid "Queue full" +msgstr "Fronta plná" + +msgid "Not while on AOL" +msgstr "Ne když na AOL" + #. Translators: This string is a menu option that, if selected, will cause #. you to appear online to the chosen user even when your status is set to #. Invisible. @@ -8552,14 +8572,14 @@ msgid "Select Server" msgstr "Vyberte server" -msgid "QQ2005" -msgstr "QQ2005" +msgid "QQ2008" +msgstr "QQ2008" msgid "QQ2007" msgstr "QQ2007" -msgid "QQ2008" -msgstr "QQ2008" +msgid "QQ2005" +msgstr "QQ2005" msgid "Connect by TCP" msgstr "Připojit se pomocí TCP" @@ -8573,6 +8593,9 @@ msgid "Show chat room when msg comes" msgstr "Zobrazit místnost při přijetí zprávy" +msgid "Use default font" +msgstr "Použít výchozí font" + msgid "Keep alive interval (seconds)" msgstr "Interval udržování naživu (v sekundách)" @@ -12088,9 +12111,6 @@ msgid "Fatal Error" msgstr "Fatální chyba" -msgid "bug master" -msgstr "lovec chyb" - msgid "artist" msgstr "umělec" @@ -12270,6 +12290,9 @@ msgid "Maithili" msgstr "Maithili" +msgid "Meadow Mari" +msgstr "Meadow Mari" + msgid "Macedonian" msgstr "Makedonština" @@ -15350,6 +15373,12 @@ msgid "You do not have permission to uninstall this application." msgstr "Nemáte oprávnění k odinstalaci této aplikace." +#~ msgid "Automatically reject from users not in buddy list" +#~ msgstr "Automaticky odmítat od uživatelů, kteří nejsou na seznamu kamarádů" + +#~ msgid "bug master" +#~ msgstr "lovec chyb" + #~ msgid "Error requesting %s" #~ msgstr "Chyba žádosti %s" diff -r a92f4cb593a4 -r 974722699032 po/de.po --- a/po/de.po Wed Feb 02 23:26:42 2011 +0000 +++ b/po/de.po Mon Apr 25 20:13:05 2011 +0000 @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: de\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-01-25 20:46+0100\n" -"PO-Revision-Date: 2011-01-25 20:46+0100\n" +"POT-Creation-Date: 2011-03-06 12:25+0100\n" +"PO-Revision-Date: 2011-03-06 12:25+0100\n" "Last-Translator: Jochen Kemnade \n" "Language-Team: German \n" "Language: de\n" @@ -3239,9 +3239,7 @@ msgstr "UIN" #. first name -#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) ); #. optional information -#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title ); msgid "First Name" msgstr "Vorname" @@ -4010,7 +4008,6 @@ msgid "Postal Code" msgstr "Postleitzahl" -#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email ); msgid "Country" msgstr "Land" @@ -6148,6 +6145,9 @@ msgid "Connecting..." msgstr "Verbinde..." +msgid "The Display Name you entered is too short." +msgstr "Der eingegebene Anzeigename ist zu kurz." + msgid "The PIN you entered has an invalid length [7-10]." msgstr "Die eingegebene PIN hat eine ungültige Länge [7-10]." @@ -6227,33 +6227,6 @@ msgid "Retrieving User Information..." msgstr "Abrufen der Benutzerinformationen..." -msgid "Loading menu..." -msgstr "Lade das Menü..." - -msgid "Status Message" -msgstr "Status-Nachricht" - -msgid "Rejection Message" -msgstr "Ablehnungsnachricht" - -#. hidden number -msgid "Hidden Number" -msgstr "Versteckte Nummer" - -msgid "Your MXit ID..." -msgstr "Ihre MXit-ID..." - -#. Configuration options -#. WAP server (reference: "libpurple/accountopt.h") -msgid "WAP Server" -msgstr "WAP-Server" - -msgid "Connect via HTTP" -msgstr "Über HTTP verbinden" - -msgid "Enable splash-screen popup" -msgstr "Startbildschirm-Popup aktivieren" - #. you were kicked msgid "You have been kicked from this MultiMX." msgstr "Sie wurden von MultiMX hinausgeworfen." @@ -6268,6 +6241,43 @@ msgid "You have invited" msgstr "Sie haben eingeladen" +msgid "Loading menu..." +msgstr "Lade das Menü..." + +msgid "Status Message" +msgstr "Status-Nachricht" + +msgid "Rejection Message" +msgstr "Ablehnungsnachricht" + +#. hidden number +msgid "Hidden Number" +msgstr "Versteckte Nummer" + +msgid "No profile available" +msgstr "Kein Profil verfügbar" + +msgid "This contact does not have a profile." +msgstr "Dieser Kontakt hat kein Profil." + +msgid "Your MXit ID..." +msgstr "Ihre MXit-ID..." + +#. contact is in Deleted, Rejected or None state +msgid "Re-Invite" +msgstr "Erneut einladen" + +#. Configuration options +#. WAP server (reference: "libpurple/accountopt.h") +msgid "WAP Server" +msgstr "WAP-Server" + +msgid "Connect via HTTP" +msgstr "Über HTTP verbinden" + +msgid "Enable splash-screen popup" +msgstr "Startbildschirm-Popup aktivieren" + msgid "Last Online" msgstr "Zuletzt online" @@ -7571,6 +7581,14 @@ msgid "You have been disconnected from chat room %s." msgstr "Die Verbindung zum Raum %s wurde unterbrochen." +msgid "The new formatting is invalid." +msgstr "Die neue Formatierung ist ungültig." + +msgid "Username formatting can change only capitalization and whitespace." +msgstr "" +"Benutzernamen-Formatierung kann nur die Groß-/Kleinschreibung und " +"Leerzeichen ändern." + msgid "Pop-Up Message" msgstr "Pop-Up Nachricht" @@ -7846,14 +7864,6 @@ msgid "ICQ Privacy Options" msgstr "ICQ Privatsphärenoptionen" -msgid "The new formatting is invalid." -msgstr "Die neue Formatierung ist ungültig." - -msgid "Username formatting can change only capitalization and whitespace." -msgstr "" -"Benutzernamen-Formatierung kann nur die Groß-/Kleinschreibung und " -"Leerzeichen ändern." - msgid "Change Address To:" msgstr "Ändere die Adresse zu:" @@ -7961,75 +7971,6 @@ "ist notwendig für IM-Bilder. Da Ihre IP-Adresse verwendet wird, kann dies " "eine Verletzung der Privatsphäre bedeuten." -msgid "Invalid SNAC" -msgstr "Ungültiger SNAC" - -msgid "Server rate limit exceeded" -msgstr "Server-Datenrate überschritten" - -msgid "Client rate limit exceeded" -msgstr "Client-Datenrate überschritten" - -msgid "Service unavailable" -msgstr "Dienst nicht verfügbar" - -msgid "Service not defined" -msgstr "Dienst nicht definiert" - -msgid "Obsolete SNAC" -msgstr "Obsoleter SNAC" - -msgid "Not supported by host" -msgstr "Nicht unterstützt vom Host" - -msgid "Not supported by client" -msgstr "Nicht unterstützt vom Client" - -msgid "Refused by client" -msgstr "Abgelehnt vom Client" - -msgid "Reply too big" -msgstr "Antwort zu groß" - -msgid "Responses lost" -msgstr "Antworten verloren" - -msgid "Request denied" -msgstr "Anfrage verweigert" - -msgid "Busted SNAC payload" -msgstr "Ruinierte SNAC-Daten" - -msgid "Insufficient rights" -msgstr "Ungenügende Rechte" - -msgid "In local permit/deny" -msgstr "In lokaler erlaubt/verboten-Liste" - -msgid "Warning level too high (sender)" -msgstr "Warnstufe zu hoch (Absender)" - -msgid "Warning level too high (receiver)" -msgstr "Warnstufe zu hoch (Empfänger)" - -msgid "User temporarily unavailable" -msgstr "Benutzer ist temporär nicht verfügbar" - -msgid "No match" -msgstr "Keine Übereinstimmung" - -msgid "List overflow" -msgstr "Listenüberlauf" - -msgid "Request ambiguous" -msgstr "Anfrage ist nicht eindeutig" - -msgid "Queue full" -msgstr "Warteschlange voll" - -msgid "Not while on AOL" -msgstr "Nicht solange bei AOL angemeldet" - #. Label msgid "Buddy Icon" msgstr "Buddy-Icon" @@ -8148,6 +8089,75 @@ msgid "Capabilities" msgstr "Fähigkeiten" +msgid "Invalid SNAC" +msgstr "Ungültiger SNAC" + +msgid "Server rate limit exceeded" +msgstr "Server-Datenrate überschritten" + +msgid "Client rate limit exceeded" +msgstr "Client-Datenrate überschritten" + +msgid "Service unavailable" +msgstr "Dienst nicht verfügbar" + +msgid "Service not defined" +msgstr "Dienst nicht definiert" + +msgid "Obsolete SNAC" +msgstr "Obsoleter SNAC" + +msgid "Not supported by host" +msgstr "Nicht unterstützt vom Host" + +msgid "Not supported by client" +msgstr "Nicht unterstützt vom Client" + +msgid "Refused by client" +msgstr "Abgelehnt vom Client" + +msgid "Reply too big" +msgstr "Antwort zu groß" + +msgid "Responses lost" +msgstr "Antworten verloren" + +msgid "Request denied" +msgstr "Anfrage verweigert" + +msgid "Busted SNAC payload" +msgstr "Ruinierte SNAC-Daten" + +msgid "Insufficient rights" +msgstr "Ungenügende Rechte" + +msgid "In local permit/deny" +msgstr "In lokaler erlaubt/verboten-Liste" + +msgid "Warning level too high (sender)" +msgstr "Warnstufe zu hoch (Absender)" + +msgid "Warning level too high (receiver)" +msgstr "Warnstufe zu hoch (Empfänger)" + +msgid "User temporarily unavailable" +msgstr "Benutzer ist temporär nicht verfügbar" + +msgid "No match" +msgstr "Keine Übereinstimmung" + +msgid "List overflow" +msgstr "Listenüberlauf" + +msgid "Request ambiguous" +msgstr "Anfrage ist nicht eindeutig" + +msgid "Queue full" +msgstr "Warteschlange voll" + +msgid "Not while on AOL" +msgstr "Nicht solange bei AOL angemeldet" + #. Translators: This string is a menu option that, if selected, will cause #. you to appear online to the chosen user even when your status is set to #. Invisible. @@ -8762,6 +8772,9 @@ msgid "Show chat room when msg comes" msgstr "Chatraum zeigen, wenn Nachricht empfangen wird" +msgid "Use default font" +msgstr "Standardschriftart benutzen" + msgid "Keep alive interval (seconds)" msgstr "Intervall zum Aufrechterhalten der Verbindung (Sekunden)" diff -r a92f4cb593a4 -r 974722699032 po/es.po --- a/po/es.po Wed Feb 02 23:26:42 2011 +0000 +++ b/po/es.po Mon Apr 25 20:13:05 2011 +0000 @@ -7,7 +7,7 @@ # , 2003. # Copyright (C) February 2010, Francisco Javier F. Serrador # Copyright (C) June 2002, April 2003, January 2004, March 2004, September 2004, -# January 2005, 2006-2008, July 2009, July 2010, August 2010 +# January 2005, 2006-2008, July 2009, July 2010, August 2010, January 2011 # Javier Fernández-Sanguino Peña # # Agradecemos la ayuda de revisión realizada por: @@ -53,8 +53,8 @@ msgstr "" "Project-Id-Version: Pidgin\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-12-19 13:33-0500\n" -"PO-Revision-Date: 2010-12-15 03:32+0100\n" +"POT-Creation-Date: 2011-02-02 23:34-0500\n" +"PO-Revision-Date: 2011-01-30 21:28+0100\n" "Last-Translator: Javier Fernández-Sanguino \n" "Language-Team: Spanish team \n" "Language: \n" @@ -2475,10 +2475,12 @@ "Ruta donde se guardarán los archivos\n" "(Debe dar la ruta completa)" -msgid "Automatically reject from users not in buddy list" -msgstr "" -"Rechazar automáticamente las transferencias de usuarios que no están en mi " -"lista de amigos" +msgid "" +"When a file-transfer request arrives from a user who is\n" +"*not* on your buddy list:" +msgstr "" +"Cuando llega una solicitud de transferencia de un usuario que\n" +"*no* está en su lista de amigos:" msgid "" "Notify with a popup when an autoaccepted file transfer is complete\n" @@ -2491,6 +2493,9 @@ msgid "Create a new directory for each user" msgstr "Crear un directorio para cada usuario" +msgid "Escape the filenames" +msgstr "Indentar los nombres de fichero" + msgid "Notes" msgstr "Notas" @@ -3954,7 +3959,10 @@ msgid "Server requires plaintext authentication over an unencrypted stream" msgstr "El servidor solicita autenticación en claro sobre un canal no cifrado" -#. This should never happen! +#. This happens when the server sends back jibberish +#. * in the "additional data with success" case. +#. * Seen with Wildfire 3.0.1. +#. msgid "Invalid response from server" msgstr "Respuesta inválida del servidor" @@ -6298,6 +6306,20 @@ msgid "Retrieving User Information..." msgstr "Obteniendo la información del usuario..." +#. you were kicked +msgid "You have been kicked from this MultiMX." +msgstr "Ha sido expulsado de este MultiMX." + +msgid "was kicked" +msgstr "fue expulsado" + +msgid "_Room Name:" +msgstr "Nombre de _Sala:" + +#. Display system message in chat window +msgid "You have invited" +msgstr "Ha sido invitado" + msgid "Loading menu..." msgstr "Cargando el menú..." @@ -6325,20 +6347,6 @@ msgid "Enable splash-screen popup" msgstr "Activar la pantalla de bienvenida" -#. you were kicked -msgid "You have been kicked from this MultiMX." -msgstr "Ha sido expulsado de este MultiMX." - -msgid "was kicked" -msgstr "fue expulsado" - -msgid "_Room Name:" -msgstr "Nombre de _Sala:" - -#. Display system message in chat window -msgid "You have invited" -msgstr "Ha sido invitado" - msgid "Last Online" msgstr "Última conexión" @@ -8007,75 +8015,6 @@ "para Imágenes de MI. Como su dirección IP será revelada, puede considerarse " "esto como un riesgo a su privacidad." -msgid "Invalid SNAC" -msgstr "SNAC inválido" - -msgid "Server rate limit exceeded" -msgstr "Se excedió el límite de tasa del servidor" - -msgid "Client rate limit exceeded" -msgstr "Se excedió el límite de tasa del cliente" - -msgid "Service unavailable" -msgstr "Servicio no disponible" - -msgid "Service not defined" -msgstr "Servicio no definido" - -msgid "Obsolete SNAC" -msgstr "SNAC obsoleto" - -msgid "Not supported by host" -msgstr "No soportado por el servidor" - -msgid "Not supported by client" -msgstr "No soportado por el cliente" - -msgid "Refused by client" -msgstr "Rechazado por el cliente" - -msgid "Reply too big" -msgstr "Respuesta demasiado grande" - -msgid "Responses lost" -msgstr "Respuestas perdidas" - -msgid "Request denied" -msgstr "Solicitud denegada" - -msgid "Busted SNAC payload" -msgstr "Carga de SNAC destrozada" - -msgid "Insufficient rights" -msgstr "Derechos insuficientes" - -msgid "In local permit/deny" -msgstr "En la lista local de autorizar/negar" - -msgid "Warning level too high (sender)" -msgstr "Nivel de aviso demasiado alto (emisor)" - -msgid "Warning level too high (receiver)" -msgstr "Nivel de aviso demasiado alto (receptor)" - -msgid "User temporarily unavailable" -msgstr "Usuario temporalmente no disponible" - -msgid "No match" -msgstr "No hubo coincidencia" - -msgid "List overflow" -msgstr "Desbordamiento de la lista" - -msgid "Request ambiguous" -msgstr "Solicitud ambigua" - -msgid "Queue full" -msgstr "Cola llena" - -msgid "Not while on AOL" -msgstr "No mientras esté en AOL" - #. Label msgid "Buddy Icon" msgstr "Icono de amigo" @@ -8194,6 +8133,75 @@ msgid "Capabilities" msgstr "Capacidades" +msgid "Invalid SNAC" +msgstr "SNAC inválido" + +msgid "Server rate limit exceeded" +msgstr "Se excedió el límite de tasa del servidor" + +msgid "Client rate limit exceeded" +msgstr "Se excedió el límite de tasa del cliente" + +msgid "Service unavailable" +msgstr "Servicio no disponible" + +msgid "Service not defined" +msgstr "Servicio no definido" + +msgid "Obsolete SNAC" +msgstr "SNAC obsoleto" + +msgid "Not supported by host" +msgstr "No soportado por el servidor" + +msgid "Not supported by client" +msgstr "No soportado por el cliente" + +msgid "Refused by client" +msgstr "Rechazado por el cliente" + +msgid "Reply too big" +msgstr "Respuesta demasiado grande" + +msgid "Responses lost" +msgstr "Respuestas perdidas" + +msgid "Request denied" +msgstr "Solicitud denegada" + +msgid "Busted SNAC payload" +msgstr "Carga de SNAC destrozada" + +msgid "Insufficient rights" +msgstr "Derechos insuficientes" + +msgid "In local permit/deny" +msgstr "En la lista local de autorizar/negar" + +msgid "Warning level too high (sender)" +msgstr "Nivel de aviso demasiado alto (emisor)" + +msgid "Warning level too high (receiver)" +msgstr "Nivel de aviso demasiado alto (receptor)" + +msgid "User temporarily unavailable" +msgstr "Usuario temporalmente no disponible" + +msgid "No match" +msgstr "No hubo coincidencia" + +msgid "List overflow" +msgstr "Desbordamiento de la lista" + +msgid "Request ambiguous" +msgstr "Solicitud ambigua" + +msgid "Queue full" +msgstr "Cola llena" + +msgid "Not while on AOL" +msgstr "No mientras esté en AOL" + #. Translators: This string is a menu option that, if selected, will cause #. you to appear online to the chosen user even when your status is set to #. Invisible. @@ -8786,14 +8794,14 @@ msgid "Select Server" msgstr "Seleccionar servidor" -msgid "QQ2005" -msgstr "QQ2005" +msgid "QQ2008" +msgstr "QQ2008" msgid "QQ2007" msgstr "QQ2007" -msgid "QQ2008" -msgstr "QQ2008" +msgid "QQ2005" +msgstr "QQ2005" msgid "Connect by TCP" msgstr "Conectar por TCP" @@ -12353,9 +12361,6 @@ msgid "Fatal Error" msgstr "Error fatal" -msgid "bug master" -msgstr "maestro de las erratas" - msgid "artist" msgstr "artista" @@ -12536,6 +12541,9 @@ msgid "Maithili" msgstr "Maithili" +msgid "Meadow Mari" +msgstr "Mari" + msgid "Macedonian" msgstr "Macedonio" @@ -15685,6 +15693,14 @@ msgid "You do not have permission to uninstall this application." msgstr "No tiene permisos para desinstalar esta aplicación." +#~ msgid "Automatically reject from users not in buddy list" +#~ msgstr "" +#~ "Rechazar automáticamente las transferencias de usuarios que no están en " +#~ "mi lista de amigos" + +#~ msgid "bug master" +#~ msgstr "maestro de las erratas" + #~ msgid "Error requesting %s" #~ msgstr "Error al solicitar %s" @@ -15757,20 +15773,20 @@ #~ msgstr "Album" #~ msgid "Current Mood" -#~ msgstr "Luna actual" +#~ msgstr "Estado de ánimo actual" #~ msgid "New Mood" -#~ msgstr "Luna nueva" +#~ msgstr "Nuevo estado de ánimo" #~ msgid "Change your Mood" -#~ msgstr "Cambiar su luna" +#~ msgstr "Cambiar su estado de ánimo" #~ msgid "How do you feel right now?" #~ msgstr "¿Cómo se encuentra justo ahora?" #, fuzzy #~ msgid "Change Mood..." -#~ msgstr "Cambiar su contraseña..." +#~ msgstr "Cambiar su estado de ánimo..." #~ msgid "Pager server" #~ msgstr "Servidor buscapersonas" diff -r a92f4cb593a4 -r 974722699032 po/he.po --- a/po/he.po Wed Feb 02 23:26:42 2011 +0000 +++ b/po/he.po Mon Apr 25 20:13:05 2011 +0000 @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: he\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-12-19 13:33-0500\n" -"PO-Revision-Date: 2010-12-16 16:39+0200\n" +"POT-Creation-Date: 2011-02-02 23:34-0500\n" +"PO-Revision-Date: 2011-01-26 08:34+0200\n" "Last-Translator: Shalom Craimer \n" "Language-Team: Hebrew \n" "Language: he\n" @@ -2278,8 +2278,12 @@ "נתיב לשמור בו את הקבצים\n" "(יש לספק נתיב מלא)" -msgid "Automatically reject from users not in buddy list" -msgstr "דחה אוטומטית ממשתמשים שאינם ברשימת החברים שלי" +msgid "" +"When a file-transfer request arrives from a user who is\n" +"*not* on your buddy list:" +msgstr "" +"כאשר מגיעה בקשה להעברת-קובץ ממשתמש\n" +"אשר *אינו* ברשימת החברים שלך:" msgid "" "Notify with a popup when an autoaccepted file transfer is complete\n" @@ -2291,6 +2295,9 @@ msgid "Create a new directory for each user" msgstr "צור ספרייה חדשה עבור כל משתמש" +msgid "Escape the filenames" +msgstr "קדד אותיות בעייתיות בשמות הקבצים" + msgid "Notes" msgstr "הערות" @@ -3724,7 +3731,10 @@ msgid "Server requires plaintext authentication over an unencrypted stream" msgstr "השרת דורש אימות לא מוצפן מעל תקשורת לא מוצפנת" -#. This should never happen! +#. This happens when the server sends back jibberish +#. * in the "additional data with success" case. +#. * Seen with Wildfire 3.0.1. +#. msgid "Invalid response from server" msgstr "תגובה לא תקפה מהשרת" @@ -5980,6 +5990,20 @@ msgid "Retrieving User Information..." msgstr "שולף מידע משתמש..." +#. you were kicked +msgid "You have been kicked from this MultiMX." +msgstr "נבעטת מתוך MultiMX זה." + +msgid "was kicked" +msgstr "נבעט/ה" + +msgid "_Room Name:" +msgstr "שם _חדר:" + +#. Display system message in chat window +msgid "You have invited" +msgstr "הוזמנת" + msgid "Loading menu..." msgstr "טוען תפריט..." @@ -6007,20 +6031,6 @@ msgid "Enable splash-screen popup" msgstr "אפשר פתיחת חלון-הקדמה" -#. you were kicked -msgid "You have been kicked from this MultiMX." -msgstr "נבעטת מתוך MultiMX זה." - -msgid "was kicked" -msgstr "נבעט/ה" - -msgid "_Room Name:" -msgstr "שם _חדר:" - -#. Display system message in chat window -msgid "You have invited" -msgstr "הוזמנת" - msgid "Last Online" msgstr "חיבור אחרון" @@ -7620,75 +7630,6 @@ "זה דורש חיבור ישיר בין שני המחשבים, ונחוץ עבור תמונות בהודעות. מכיוון שכתובת " "ה-IP שלך תיחשף, ייתכן וזה ייחשב כסיכון לפרטיותך." -msgid "Invalid SNAC" -msgstr "SNAC לא תקף" - -msgid "Server rate limit exceeded" -msgstr "הפרזת מעבר למגבלת השרת" - -msgid "Client rate limit exceeded" -msgstr "הפרזת מעבר למגבלת הלקוח" - -msgid "Service unavailable" -msgstr "השירות אינו זמין" - -msgid "Service not defined" -msgstr "שירות אינו מוגדר" - -msgid "Obsolete SNAC" -msgstr "SNAC מיושן" - -msgid "Not supported by host" -msgstr "לא נתמך על-ידי השרת" - -msgid "Not supported by client" -msgstr "לא נתמך על-ידי הלקוח" - -msgid "Refused by client" -msgstr "החיבור נדחה על ידי הלקוח." - -msgid "Reply too big" -msgstr "המענה גדול מדיי" - -msgid "Responses lost" -msgstr "אבדו המשובים" - -msgid "Request denied" -msgstr "הבקשה נדחית" - -msgid "Busted SNAC payload" -msgstr "מידע פגום ב-SNAC" - -msgid "Insufficient rights" -msgstr "אין די הרשאות" - -msgid "In local permit/deny" -msgstr "באישור/שלילה מקומיים" - -msgid "Warning level too high (sender)" -msgstr "רמת אזהרה גבוהה מדי (שולח(" - -msgid "Warning level too high (receiver)" -msgstr "רמת אזהרה גבוהה מדי (מקבל)" - -msgid "User temporarily unavailable" -msgstr "המשתמש אינו זמין כרגע" - -msgid "No match" -msgstr "אין התאמה" - -msgid "List overflow" -msgstr "גלישת מגבולות הרשימה" - -msgid "Request ambiguous" -msgstr "בקשה לא ברורה" - -msgid "Queue full" -msgstr "התור מלא" - -msgid "Not while on AOL" -msgstr "לא בזמן שהות ב-AOL" - #. Label msgid "Buddy Icon" msgstr "סמל איש הקשר" @@ -7807,6 +7748,75 @@ msgid "Capabilities" msgstr "יכולות" +msgid "Invalid SNAC" +msgstr "SNAC לא תקף" + +msgid "Server rate limit exceeded" +msgstr "הפרזת מעבר למגבלת השרת" + +msgid "Client rate limit exceeded" +msgstr "הפרזת מעבר למגבלת הלקוח" + +msgid "Service unavailable" +msgstr "השירות אינו זמין" + +msgid "Service not defined" +msgstr "שירות אינו מוגדר" + +msgid "Obsolete SNAC" +msgstr "SNAC מיושן" + +msgid "Not supported by host" +msgstr "לא נתמך על-ידי השרת" + +msgid "Not supported by client" +msgstr "לא נתמך על-ידי הלקוח" + +msgid "Refused by client" +msgstr "החיבור נדחה על ידי הלקוח." + +msgid "Reply too big" +msgstr "המענה גדול מדיי" + +msgid "Responses lost" +msgstr "אבדו המשובים" + +msgid "Request denied" +msgstr "הבקשה נדחית" + +msgid "Busted SNAC payload" +msgstr "מידע פגום ב-SNAC" + +msgid "Insufficient rights" +msgstr "אין די הרשאות" + +msgid "In local permit/deny" +msgstr "באישור/שלילה מקומיים" + +msgid "Warning level too high (sender)" +msgstr "רמת אזהרה גבוהה מדי (שולח(" + +msgid "Warning level too high (receiver)" +msgstr "רמת אזהרה גבוהה מדי (מקבל)" + +msgid "User temporarily unavailable" +msgstr "המשתמש אינו זמין כרגע" + +msgid "No match" +msgstr "אין התאמה" + +msgid "List overflow" +msgstr "גלישת מגבולות הרשימה" + +msgid "Request ambiguous" +msgstr "בקשה לא ברורה" + +msgid "Queue full" +msgstr "התור מלא" + +msgid "Not while on AOL" +msgstr "לא בזמן שהות ב-AOL" + #. Translators: This string is a menu option that, if selected, will cause #. you to appear online to the chosen user even when your status is set to #. Invisible. @@ -8398,14 +8408,14 @@ msgid "Select Server" msgstr "בחר שרת" -msgid "QQ2005" -msgstr "QQ2005" +msgid "QQ2008" +msgstr "QQ2008" msgid "QQ2007" msgstr "QQ2007" -msgid "QQ2008" -msgstr "QQ2008" +msgid "QQ2005" +msgstr "QQ2005" msgid "Connect by TCP" msgstr "התחבר בעזרת TCP" @@ -11881,9 +11891,6 @@ msgid "Fatal Error" msgstr "שגיאה קטלנית" -msgid "bug master" -msgstr "שר-הבאגים" - msgid "artist" msgstr "אמן" @@ -12063,6 +12070,9 @@ msgid "Maithili" msgstr "מאת'ילי" +msgid "Meadow Mari" +msgstr "Meadow Mari" + msgid "Macedonian" msgstr "מקדונית" @@ -15107,6 +15117,12 @@ msgid "You do not have permission to uninstall this application." msgstr ".אין לך זכות למחוק תוכנה זאת" +#~ msgid "Automatically reject from users not in buddy list" +#~ msgstr "דחה אוטומטית ממשתמשים שאינם ברשימת החברים שלי" + +#~ msgid "bug master" +#~ msgstr "שר-הבאגים" + #~ msgid "An error occurred on the in-band bytestream transfer\n" #~ msgstr "ארעה שגיאה בעת ההעברה בזרם בתווך\n" diff -r a92f4cb593a4 -r 974722699032 po/it.po --- a/po/it.po Wed Feb 02 23:26:42 2011 +0000 +++ b/po/it.po Mon Apr 25 20:13:05 2011 +0000 @@ -1,6 +1,6 @@ # Pidgin Italian translation # Copyright (C) 2002, Salvatore di Maggio -# Copyright (C) 2003-2010, Claudio Satriano +# Copyright (C) 2003-2011, Claudio Satriano # # This file is distributed under the same license as the Pidgin package. # @@ -8,9 +8,9 @@ msgstr "" "Project-Id-Version: Pidgin\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-12-19 13:33-0500\n" -"PO-Revision-Date: 2010-05-24 12:38+0100\n" -"Last-Translator: Claudio Satriano \n" +"POT-Creation-Date: 2011-03-10 01:39-0800\n" +"PO-Revision-Date: 2011-03-07 15:26+0100\n" +"Last-Translator: Claudio Satriano \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" @@ -61,9 +61,8 @@ msgid "Error" msgstr "Errore" -#, fuzzy msgid "Account was not modified" -msgstr "L'account non è stato aggiunto" +msgstr "L'account non è stato modificato" msgid "Account was not added" msgstr "L'account non è stato aggiunto" @@ -74,10 +73,14 @@ msgid "" "The account's protocol cannot be changed while it is connected to the server." msgstr "" +"Il protocollo dell'account non può essere cambiato mentre è connesso al " +"server." msgid "" "The account's username cannot be changed while it is connected to the server." msgstr "" +"Il nome utente dell'account non può essere cambiato mentre è connesso al " +"server." msgid "New mail notifications" msgstr "Notifica i nuovi messaggi di posta" @@ -1704,13 +1707,15 @@ "The certificate is not valid yet. Check that your computer's date and time " "are accurate." msgstr "" - -#, fuzzy +"Il certificato non è ancora valido. Verifica che la data e l'ora del tuo " +"computer siano accurate." + msgid "" "The certificate has expired and should not be considered valid. Check that " "your computer's date and time are accurate." msgstr "" -"Il certificato è scaduto e non dovrebbe essere considerato come valido." +"Il certificato è scaduto e non dovrebbe essere considerato come valido. " +"Verifica che la data e l'ora del tuo computer sono accurate." #. Translators: "domain" refers to a DNS domain (e.g. talk.google.com) msgid "The certificate presented is not issued to this domain." @@ -2371,9 +2376,12 @@ "Posizione in cui salvare i file\n" "(Digitare il percorso completo)" -msgid "Automatically reject from users not in buddy list" -msgstr "" -"Rifiuta automaticamente per gli utenti non presenti nella lista contatti" +msgid "" +"When a file-transfer request arrives from a user who is\n" +"*not* on your buddy list:" +msgstr "" +"Quando arriva una richiesta di trasferimento file da\n" +"un utente che *non* è nella tua lista contatti:" msgid "" "Notify with a popup when an autoaccepted file transfer is complete\n" @@ -2386,6 +2394,9 @@ msgid "Create a new directory for each user" msgstr "Crea una nuova directory per ciascun utente" +msgid "Escape the filenames" +msgstr "Codifica i nomi dei file" + msgid "Notes" msgstr "Note" @@ -3232,9 +3243,7 @@ msgstr "UIN" #. first name -#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) ); #. optional information -#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title ); msgid "First Name" msgstr "Nome" @@ -3849,7 +3858,10 @@ "Il server richiede l'autenticazione sotto forma di testo semplice su uno " "stream non criptato" -#. This should never happen! +#. This happens when the server sends back jibberish +#. * in the "additional data with success" case. +#. * Seen with Wildfire 3.0.1. +#. msgid "Invalid response from server" msgstr "Risposta non valida da parte del server" @@ -3868,7 +3880,7 @@ msgstr "Autenticazione come testo semplice" msgid "You require encryption, but it is not available on this server." -msgstr "Hai richiesto la criptatura, ma non è disponibile su questo server." +msgstr "Hai richiesto la crittografia, ma non è disponibile su questo server." msgid "Invalid challenge from server" msgstr "Challenge non valido dal server" @@ -3876,18 +3888,17 @@ msgid "Server thinks authentication is complete, but client does not" msgstr "Il server ritiene che l'autenticazione sia completa; il client no " -#, fuzzy msgid "Server may require plaintext authentication over an unencrypted stream" msgstr "" -"Il server richiede l'autenticazione sotto forma di testo semplice su uno " -"stream non criptato" - -#, fuzzy, c-format +"Il server potrebbe richiedere l'autenticazione sotto forma di testo semplice " +"su uno stream non criptato" + +#, c-format msgid "" "%s may require plaintext authentication over an unencrypted connection. " "Allow this and continue authentication?" msgstr "" -"%s richiede l'autenticazione sotto forma di testo semplice su una " +"%s potrebbe richiedere l'autenticazione sotto forma di testo semplice su una " "connessione non criptata. Procedere con l'autenticazione?" msgid "SASL authentication failed" @@ -3995,7 +4006,6 @@ msgid "Postal Code" msgstr "Codice postale" -#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email ); msgid "Country" msgstr "Paese" @@ -4763,20 +4773,17 @@ msgid "Domain" msgstr "Dominio" -#, fuzzy msgid "Require encryption" -msgstr "Richiedi autorizzazione" - -#, fuzzy +msgstr "Richiedi crittografia" + msgid "Use encryption if available" -msgstr "Informazioni sull'utente non disponibili: %s" +msgstr "Usa crittografia, se disponibile" msgid "Use old-style SSL" -msgstr "" - -#, fuzzy +msgstr "Utilizza SSL vecchio stile" + msgid "Connection security" -msgstr "Connessione scaduta" +msgstr "Sicurezza della connessione" msgid "Allow plaintext auth over unencrypted streams" msgstr "" @@ -5443,28 +5450,23 @@ msgid "Set friendly name for %s." msgstr "Imposta un alias per %s." -#, fuzzy msgid "Set Friendly Name" -msgstr "Imposta un alias..." +msgstr "Imposta un alias" msgid "This is the name that other MSN buddies will see you as." msgstr "Questo è il nome con il quale i contatti MSN ti vedranno." -#, fuzzy msgid "This Location" -msgstr "Località" - -#, fuzzy +msgstr "Questa postazione" + msgid "This is the name that identifies this location" -msgstr "Questo è il nome con il quale i contatti MSN ti vedranno." - -#, fuzzy +msgstr "Questo è il nome che identifica questa postazione" + msgid "Other Locations" -msgstr "Località" - -#, fuzzy +msgstr "Altre postazioni" + msgid "You can sign out from other locations here" -msgstr "Sei connesso da un'altra postazione" +msgstr "Da qui puoi disconnetterti dalle altre postazioni" #. TODO: Due to limitations in our current request field API, the #. following string will show up with a trailing colon. This should @@ -5472,18 +5474,17 @@ #. a separate purple_request_field_label_new_without_colon function, #. or by never automatically adding the colon and requiring that #. callers add the colon themselves. -#, fuzzy msgid "You are not signed in from any other locations." -msgstr "Sei connesso da un'altra postazione" - -#, fuzzy +msgstr "Non sei connesso da nessun'altra postazione" + msgid "Allow multiple logins?" -msgstr "Consenti istanze multiple" +msgstr "Consenti connessioni multiple?" msgid "" "Do you want to allow or disallow connecting from multiple locations " "simultaneously?" msgstr "" +"Vuoi consentire o vietare la connessione simultanea da diverse postazioni?" msgid "Allow" msgstr "Permetti" @@ -5572,9 +5573,8 @@ msgid "Set Friendly Name..." msgstr "Imposta un alias..." -#, fuzzy msgid "View Locations..." -msgstr "Scegli posizione..." +msgstr "Guarda le postazioni..." msgid "Set Home Phone Number..." msgstr "Imposta il telefono di casa..." @@ -5588,9 +5588,8 @@ msgid "Enable/Disable Mobile Devices..." msgstr "Abilita/Disabilita i dispositivi portatili..." -#, fuzzy msgid "Allow/Disallow Multiple Logins..." -msgstr "Permetti/Vieta Mobile Pages..." +msgstr "Permetti/Vieta le connessioni multiple..." msgid "Allow/Disallow Mobile Pages..." msgstr "Permetti/Vieta Mobile Pages..." @@ -5811,7 +5810,7 @@ msgstr "Consenti connessioni dirette" msgid "Allow connecting from multiple locations" -msgstr "" +msgstr "Consenti la connessione da diverse postazioni" msgid "nudge: nudge a user to get their attention" msgstr "nudge: Richiama l'attenzione di un contatto con un trillo" @@ -6026,9 +6025,8 @@ msgid "The two PINs you entered do not match." msgstr "I due PIN immessi non corrispondono." -#, fuzzy msgid "The Display Name you entered is invalid." -msgstr "Il nome immesso non è valido." +msgstr "Il nome utente immesso non è valido." msgid "" "The birthday you entered is invalid. The correct format is: 'YYYY-MM-DD'." @@ -6050,9 +6048,8 @@ "L'informazione sul tuo profilo non è stata ancora recuperata. Riprova più " "tardi." -#, fuzzy msgid "Your UID" -msgstr "Il tuo ID MXit" +msgstr "Il tuo UID" #. pin #. pin (required) @@ -6123,12 +6120,15 @@ msgid "Connecting..." msgstr "Connessione in corso..." +msgid "The Display Name you entered is too short." +msgstr "Il nome utente immesso è troppo corto." + msgid "The PIN you entered has an invalid length [7-10]." msgstr "Il PIN immesso ha una lunghezza non valida [7-10]." #. mxit login name msgid "MXit ID" -msgstr "" +msgstr "ID MXit" #. show the form to the user to complete msgid "Register New MXit Account" @@ -6157,13 +6157,11 @@ msgid "Invalid country selected. Please try again." msgstr "Paese selezionato non valido. Riprova più tardi." -#, fuzzy msgid "The MXit ID you entered is not registered. Please register first." -msgstr "Il nome utente non è registrato. Registrati prima." - -#, fuzzy +msgstr "L'ID MXit immesso non è registrato. Registrati prima." + msgid "The MXit ID you entered is already registered. Please choose another." -msgstr "Il nome utente è già registrato. Scegli un altro nome utente." +msgstr "L'ID MXit immesso è già registrato. Scegline un altro." msgid "Internal error. Please try again later." msgstr "Errore interno. Riprovare più tardi" @@ -6194,6 +6192,20 @@ msgid "Retrieving User Information..." msgstr "Scaricamento in corso delle informazioni sull'utente..." +#. you were kicked +msgid "You have been kicked from this MultiMX." +msgstr "Sei stato cacciato da questo MultiMX." + +msgid "was kicked" +msgstr "è stato cacciato" + +msgid "_Room Name:" +msgstr "Nome della _Stanza:" + +#. Display system message in chat window +msgid "You have invited" +msgstr "Hai invitato" + msgid "Loading menu..." msgstr "Caricamento del menu in corso..." @@ -6207,9 +6219,18 @@ msgid "Hidden Number" msgstr "Numero nascosto" -#, fuzzy +msgid "No profile available" +msgstr "Nessun profilo disponibile" + +msgid "This contact does not have a profile." +msgstr "Questo contatto non ha un profilo." + msgid "Your MXit ID..." -msgstr "Il tuo ID MXit" +msgstr "Il tuo ID MXit..." + +#. contact is in Deleted, Rejected or None state +msgid "Re-Invite" +msgstr "Invita di nuovo" #. Configuration options #. WAP server (reference: "libpurple/accountopt.h") @@ -6222,27 +6243,8 @@ msgid "Enable splash-screen popup" msgstr "Abilita lo splash screen" -#. you were kicked -#, fuzzy -msgid "You have been kicked from this MultiMX." -msgstr "Sei stato cacciato: (%s)" - -#, fuzzy -msgid "was kicked" -msgstr "Biglietto non valido" - -#, fuzzy -msgid "_Room Name:" -msgstr "_Stanza:" - -#. Display system message in chat window -#, fuzzy -msgid "You have invited" -msgstr "C'è posta per te!" - -#, fuzzy msgid "Last Online" -msgstr "Online" +msgstr "Connesso l'ultima volta" #. we must have lost the connection, so terminate it so that we can reconnect msgid "We have lost the connection to MXit. Please reconnect." @@ -7009,6 +7011,8 @@ "You required encryption in your account settings, but one of the servers " "doesn't support it." msgstr "" +"Hai richiesto la crittografia nelle impostazioni del tuo account, ma uno dei " +"server non la supporta." #. Note to translators: The first %s is a URL, the second is an #. error message. @@ -7016,9 +7020,8 @@ msgid "Error requesting %s: %s" msgstr "Errore nella richiesta di %s: %s" -#, fuzzy msgid "The server returned an empty response" -msgstr "Impossibile connettersi: il server ha fornito una risposta vuota." +msgstr "Il server ha fornito una risposta vuota" msgid "" "Server requested that you fill out a CAPTCHA in order to sign in, but this " @@ -7328,6 +7331,8 @@ "You required encryption in your account settings, but encryption is not " "supported by your system." msgstr "" +"Hai richiesto la crittografia nelle impostazioni del tuo account, ma la " +"crittografia non è supportata dal tuo sistema." #, c-format msgid "You may be disconnected shortly. If so, check %s for updates." @@ -7528,6 +7533,14 @@ msgid "You have been disconnected from chat room %s." msgstr "Sei stato disconnesso dalla stanza di discussione %s." +msgid "The new formatting is invalid." +msgstr "La nuova formattazione non è valida." + +msgid "Username formatting can change only capitalization and whitespace." +msgstr "" +"La formattazione del nome utente può modificare solo le maiuscole/minuscole " +"e gli spazi bianchi." + msgid "Pop-Up Message" msgstr "Messaggio pop-up" @@ -7802,20 +7815,11 @@ msgid "ICQ Privacy Options" msgstr "Opzioni per la privacy di ICQ" -msgid "The new formatting is invalid." -msgstr "La nuova formattazione non è valida." - -msgid "Username formatting can change only capitalization and whitespace." -msgstr "" -"La formattazione del nome utente può modificare solo le maiuscole/minuscole " -"e gli spazi bianchi." - msgid "Change Address To:" msgstr "Cambia l'indirizzo in:" -#, fuzzy msgid "you are not waiting for authorization" -msgstr "non stai attendendo nessuna autorizzazione" +msgstr "non stai attendendo nessuna autorizzazione" msgid "You are awaiting authorization from the following buddies" msgstr "Stai attendendo autorizzazione dai seguenti contatti" @@ -7853,13 +7857,11 @@ msgid "Set Privacy Options..." msgstr "Imposta le opzioni per la privacy..." -#, fuzzy msgid "Show Visible List" -msgstr "Mostra la _lista contatti" - -#, fuzzy +msgstr "Mostra la lista \"visibile\"" + msgid "Show Invisible List" -msgstr "Lista degli inviti" +msgstr "Mostra la lista \"invisibile\"" #. AIM actions msgid "Confirm Account" @@ -7877,9 +7879,8 @@ msgid "Search for Buddy by Email Address..." msgstr "Cerca un contatto per indirizzo email..." -#, fuzzy msgid "Don't use encryption" -msgstr "Richiedi autorizzazione" +msgstr "Non usare la crittografia" msgid "Use clientLogin" msgstr "Usa clientLogin" @@ -7922,86 +7923,6 @@ "per le Immagini IM. Poiché verrà rivelato il tuo indirizzo IP, devi " "considerare la cosa come un potenziale rischio per la tua privacy." -#, fuzzy -msgid "Invalid SNAC" -msgstr "ID non valido" - -msgid "Server rate limit exceeded" -msgstr "" - -msgid "Client rate limit exceeded" -msgstr "" - -#, fuzzy -msgid "Service unavailable" -msgstr "Servizio non disponibile" - -#, fuzzy -msgid "Service not defined" -msgstr "Conferenza non trovata" - -msgid "Obsolete SNAC" -msgstr "" - -#, fuzzy -msgid "Not supported by host" -msgstr "Non supportato" - -#, fuzzy -msgid "Not supported by client" -msgstr "Non supportato" - -msgid "Refused by client" -msgstr "" - -msgid "Reply too big" -msgstr "" - -#, fuzzy -msgid "Responses lost" -msgstr "Probabilità di risposta:" - -#, fuzzy -msgid "Request denied" -msgstr "Richiesta in corso" - -msgid "Busted SNAC payload" -msgstr "" - -msgid "Insufficient rights" -msgstr "" - -msgid "In local permit/deny" -msgstr "" - -msgid "Warning level too high (sender)" -msgstr "" - -msgid "Warning level too high (receiver)" -msgstr "" - -#, fuzzy -msgid "User temporarily unavailable" -msgstr "Servizio temporaneamente non disponibile" - -#, fuzzy -msgid "No match" -msgstr "Nessuna corrispondenza" - -#, fuzzy -msgid "List overflow" -msgstr "Lista piena" - -#, fuzzy -msgid "Request ambiguous" -msgstr "Richiesta in corso" - -msgid "Queue full" -msgstr "" - -msgid "Not while on AOL" -msgstr "" - #. Label msgid "Buddy Icon" msgstr "Icona per il contatto" @@ -8046,7 +7967,7 @@ msgstr "Vecchio ICQ UTF8" msgid "Trillian Encryption" -msgstr "Crittazione di trillian" +msgstr "Crittografia di Trillian" msgid "ICQ UTF8" msgstr "ICQ UTF8" @@ -8120,58 +8041,123 @@ msgid "Capabilities" msgstr "Capacità" +msgid "Invalid SNAC" +msgstr "SNAC non valido" + +msgid "Server rate limit exceeded" +msgstr "Velocità del server superata" + +msgid "Client rate limit exceeded" +msgstr "Velocità del client superata" + +msgid "Service unavailable" +msgstr "Servizio non disponibile" + +msgid "Service not defined" +msgstr "Servizio non definito" + +msgid "Obsolete SNAC" +msgstr "SNAC obsoleto" + +msgid "Not supported by host" +msgstr "Non supportato dal server" + +msgid "Not supported by client" +msgstr "Non supportato dal client" + +msgid "Refused by client" +msgstr "Rifiutato dal client" + +msgid "Reply too big" +msgstr "Risposta troppo grande" + +msgid "Responses lost" +msgstr "Risposte perse" + +msgid "Request denied" +msgstr "Richiesta negata" + +msgid "Busted SNAC payload" +msgstr "" + +msgid "Insufficient rights" +msgstr "Permessi insufficienti" + +msgid "In local permit/deny" +msgstr "" + +msgid "Warning level too high (sender)" +msgstr "Livello di allerta troppo elevato (mittente)" + +msgid "Warning level too high (receiver)" +msgstr "Livello di allerta troppo elevato (destinatario)" + +msgid "User temporarily unavailable" +msgstr "Utente temporaneamente non disponibile" + +msgid "No match" +msgstr "Nessuna corrispondenza" + +msgid "List overflow" +msgstr "Overflow della lista" + +msgid "Request ambiguous" +msgstr "Richiesta ambigua" + +msgid "Queue full" +msgstr "Coda piena" + +msgid "Not while on AOL" +msgstr "Non possibile su AOL" + #. Translators: This string is a menu option that, if selected, will cause #. you to appear online to the chosen user even when your status is set to #. Invisible. msgid "Appear Online" -msgstr "Appai come in linea" +msgstr "Mostrati come in linea" #. Translators: This string is a menu option that, if selected, will cause #. you to appear offline to the chosen user when your status is set to #. Invisible (this is the default). -#, fuzzy msgid "Don't Appear Online" -msgstr "Appai come in linea" +msgstr "Non mostrarti come in linea" #. Translators: This string is a menu option that, if selected, will cause #. you to always appear offline to the chosen user (even when your status #. isn't Invisible). msgid "Appear Offline" -msgstr "Sembra non in linea" +msgstr "Mostrati come non in linea" #. Translators: This string is a menu option that, if selected, will cause #. you to appear offline to the chosen user if you are invisible, and #. appear online to the chosen user if you are not invisible (this is the #. default). -#, fuzzy msgid "Don't Appear Offline" -msgstr "Sembra non in linea" - -#, fuzzy +msgstr "Non mostrarti come non in linea" + msgid "you have no buddies on this list" -msgstr "Sei stato cacciato: (%s)" - -#, fuzzy, c-format +msgstr "non hai nessun contatto su questa lista" + +#, c-format msgid "" "You can add a buddy to this list by right-clicking on them and selecting \"%s" "\"" msgstr "" -"Puoi richiedere nuovamente autorizzazione da questi contatti cliccando col " -"tasto destro su di essi e scegliendo \"Richiedi nuovamente autorizzazione\"" - -#, fuzzy +"Puoi aggiungere un contatto a questa lista facendo clic con il pulsante " +"destro sul suo nome e scegliendo \"%s\"" + msgid "Visible List" -msgstr "Visibile" +msgstr "Lista \"visibile\"" msgid "These buddies will see your status when you switch to \"Invisible\"" msgstr "" - -#, fuzzy +"Questi contatti potranno vedere il tuo stato quando passi a \"Invisibile\"" + msgid "Invisible List" -msgstr "Lista degli inviti" +msgstr "Lista \"invisibile\"" msgid "These buddies will always see you as offline" -msgstr "" +msgstr "Questi contatti ti vedranno sempre come non in linea" msgid "Aquarius" msgstr "Acquario" @@ -8351,9 +8337,9 @@ msgid "Your request was rejected." msgstr "La tua richiesta è stata rifiutata." -#, fuzzy, c-format +#, c-format msgid "%u requires verification: %s" -msgstr "%u necessita di verifica" +msgstr "%u necessita di verifica: %s" msgid "Add buddy question" msgstr "Domanda per l'aggiunta del contatto" @@ -8716,14 +8702,14 @@ msgid "Select Server" msgstr "Scegli un server" -msgid "QQ2005" -msgstr "QQ2005" +msgid "QQ2008" +msgstr "QQ2008" msgid "QQ2007" msgstr "QQ2007" -msgid "QQ2008" -msgstr "QQ2008" +msgid "QQ2005" +msgstr "QQ2005" msgid "Connect by TCP" msgstr "Connetti utilizzando TCP" @@ -8737,6 +8723,9 @@ msgid "Show chat room when msg comes" msgstr "Mostra la stanza di discussione all'arrivo di un messaggio" +msgid "Use default font" +msgstr "Usa il carattere predefinito" + msgid "Keep alive interval (seconds)" msgstr "Intervallo di \"Keep alive\" (secondi)" @@ -10384,9 +10373,8 @@ msgid "Ignore conference and chatroom invitations" msgstr "Ignora gli inviti a conferenze e a stanze di discussione" -#, fuzzy msgid "Use account proxy for HTTP and HTTPS connections" -msgstr "Usa un account proxy per le connessioni SSL" +msgstr "Usa un account proxy per le connessioni HTTP e HTTPS" msgid "Chat room list URL" msgstr "URL della lista delle stanze di discussione" @@ -10578,7 +10566,7 @@ msgstr "Non è nella lista del server" msgid "Appear Permanently Offline" -msgstr "Appai permanentemente come non in linea" +msgstr "Appari permanentemente come non in linea" msgid "Presence" msgstr "Presenza" @@ -11297,9 +11285,9 @@ "account, attraverso Account->Gestisci account nella finestra della " "Lista contatti." -#, fuzzy, c-format +#, c-format msgid "%s%s%s%s wants to add you (%s) to his or her buddy list%s%s" -msgstr "%s%s%s%s vuole aggiungere %s alla sua lista dei contatti%s%s" +msgstr "%s%s%s%s vuole aggiungerti (%s) alla sua lista dei contatti%s%s" #. Buddy List msgid "Background Color" @@ -12287,9 +12275,6 @@ msgid "Fatal Error" msgstr "Errore fatale" -msgid "bug master" -msgstr "signore dei bug" - msgid "artist" msgstr "artista" @@ -12466,9 +12451,11 @@ msgid "Lao" msgstr "Lao" -#, fuzzy msgid "Maithili" -msgstr "Swahili" +msgstr "Maithili" + +msgid "Meadow Mari" +msgstr "Meadow Mari" msgid "Macedonian" msgstr "Macedone" @@ -13259,13 +13246,11 @@ msgid "Exiting because another libpurple client is already running.\n" msgstr "Uscita in corso, poiché è in esecuzione un altro client libpurple.\n" -#, fuzzy msgid "_Media" -msgstr "/_Media" - -#, fuzzy +msgstr "_Media" + msgid "_Hangup" -msgstr "Riaggancia" +msgstr "_Riaggancia" #, c-format msgid "%s wishes to start an audio/video session with you." @@ -13323,7 +13308,7 @@ msgstr "Nuovi allarmi" msgid "Dismiss" -msgstr "Chiudi" +msgstr "Rimuovi" msgid "You have pounced!" msgstr "Hai degli avvisi!" @@ -13686,9 +13671,8 @@ msgid "_TURN server:" msgstr "Server _TURN:" -#, fuzzy msgid "_UDP Port:" -msgstr "_Porta:" +msgstr "Porta _UDP:" msgid "Use_rname:" msgstr "Nome u_tente:" @@ -13712,7 +13696,7 @@ msgstr "Konqueror" msgid "Google Chrome" -msgstr "" +msgstr "Google Chrome" #. Do not move the line below. Code below expects gnome-open to be in #. * this list immediately after xdg-open! @@ -13736,11 +13720,11 @@ #. Translators: please do not translate "chromium-browser" here! msgid "Chromium (chromium-browser)" -msgstr "" +msgstr "Chromium (chromium-browser)" #. Translators: please do not translate "chrome" here! msgid "Chromium (chrome)" -msgstr "" +msgstr "Chromium (chrome)" msgid "Manual" msgstr "Manuale" @@ -14111,7 +14095,7 @@ msgstr "Google Talk" msgid "Facebook (XMPP)" -msgstr "" +msgstr "Facebook (XMPP)" #, c-format msgid "The following error has occurred loading %s: %s" @@ -14281,9 +14265,8 @@ msgid "Small" msgstr "Piccolo" -#, fuzzy msgid "Smaller versions of the default smileys" -msgstr "Versione più piccola degli smiley predefiniti" +msgstr "Versioni più piccole degli smiley predefiniti" msgid "Response Probability:" msgstr "Probabilità di risposta:" @@ -15324,9 +15307,8 @@ msgid "Voice/Video Settings" msgstr "Impostazioni Voce/Video" -#, fuzzy msgid "Voice and Video Settings" -msgstr "Impostazioni Voce/Video" +msgstr "Impostazioni voce e video" #. *< name #. *< version @@ -15605,64 +15587,3 @@ msgid "You do not have permission to uninstall this application." msgstr "Non hai il permesso per rimuovere questa applicazione." - -#~ msgid "An error occurred on the in-band bytestream transfer\n" -#~ msgstr "" -#~ "Si è verificato un errore nel trasferimento del flusso di dati in-band\n" - -#~ msgid "Transfer was closed." -#~ msgstr "Il trasferimento è stato chiuso." - -#~ msgid "Failed to open in-band bytestream" -#~ msgstr "Impossibile aprire il flusso di byte in-band" - -#~ msgid "Set your friendly name." -#~ msgstr "Imposta un alias." - -#~ msgid "Error requesting %s" -#~ msgstr "Errore nella richiesta di %s" - -#~ msgid "Require SSL/TLS" -#~ msgstr "Richiedi SSL/TLS" - -#~ msgid "Force old (port 5223) SSL" -#~ msgstr "Forza il vecchio SSL (porta 5223)" - -#~ msgid "The name you entered is invalid." -#~ msgstr "Il nome immesso non è valido." - -#~ msgid "" -#~ "[Unable to display a message from this user because it contained invalid " -#~ "characters.]" -#~ msgstr "" -#~ "[Impossibile mostrare un messaggio da questo utente poiché contiene " -#~ "caratteri non validi.]" - -#~ msgid "Search for Buddy by Information" -#~ msgstr "Cerca un contatto per informazione" - -#~ msgid "The certificate is not valid yet." -#~ msgstr "Il certificato non è ancora valido." - -#~ msgid "The nick name you entered is invalid." -#~ msgstr "Il nickname immesso non è valido" - -#~ msgid "MXit Login Name" -#~ msgstr "Nome di login per MXit" - -#~ msgid "Nick Name" -#~ msgstr "Nickname" - -#~ msgid "Your Mobile Number..." -#~ msgstr "Il tuo numero di cellulare..." - -#, fuzzy -#~ msgid "Rate to host" -#~ msgstr "Invita in chat" - -#, fuzzy -#~ msgid "Rate to client" -#~ msgstr "Ultimo client conosciuto" - -#~ msgid "/Media/_Hangup" -#~ msgstr "/Media/_Riaggancia" diff -r a92f4cb593a4 -r 974722699032 po/l10n.xsl --- a/po/l10n.xsl Wed Feb 02 23:26:42 2011 +0000 +++ b/po/l10n.xsl Mon Apr 25 20:13:05 2011 +0000 @@ -12,7 +12,6 @@ <xsl:value-of select='@name'/> translation statistics -